xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (revision 965f88258843547d8226ec630c4b810a04a06ff4)
1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines BasicObjCFoundationChecks, a class that encapsulates
11 //  a set of simple checks to run on Objective-C code using Apple's Foundation
12 //  classes.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "ClangSACheckers.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprObjC.h"
21 #include "clang/AST/StmtObjC.h"
22 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24 #include "clang/StaticAnalyzer/Core/Checker.h"
25 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
29 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
30 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
31 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/StringMap.h"
34 #include "llvm/Support/raw_ostream.h"
35 
36 using namespace clang;
37 using namespace ento;
38 
39 namespace {
40 class APIMisuse : public BugType {
41 public:
42   APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
43 };
44 } // end anonymous namespace
45 
46 //===----------------------------------------------------------------------===//
47 // Utility functions.
48 //===----------------------------------------------------------------------===//
49 
50 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
51   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
52     return ID->getIdentifier()->getName();
53   return StringRef();
54 }
55 
56 enum FoundationClass {
57   FC_None,
58   FC_NSArray,
59   FC_NSDictionary,
60   FC_NSEnumerator,
61   FC_NSNull,
62   FC_NSOrderedSet,
63   FC_NSSet,
64   FC_NSString
65 };
66 
67 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
68                                       bool IncludeSuperclasses = true) {
69   static llvm::StringMap<FoundationClass> Classes;
70   if (Classes.empty()) {
71     Classes["NSArray"] = FC_NSArray;
72     Classes["NSDictionary"] = FC_NSDictionary;
73     Classes["NSEnumerator"] = FC_NSEnumerator;
74     Classes["NSNull"] = FC_NSNull;
75     Classes["NSOrderedSet"] = FC_NSOrderedSet;
76     Classes["NSSet"] = FC_NSSet;
77     Classes["NSString"] = FC_NSString;
78   }
79 
80   // FIXME: Should we cache this at all?
81   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
82   if (result == FC_None && IncludeSuperclasses)
83     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
84       return findKnownClass(Super);
85 
86   return result;
87 }
88 
89 //===----------------------------------------------------------------------===//
90 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
91 //===----------------------------------------------------------------------===//
92 
93 namespace {
94   class NilArgChecker : public Checker<check::PreObjCMessage,
95                                        check::PostStmt<ObjCDictionaryLiteral>,
96                                        check::PostStmt<ObjCArrayLiteral> > {
97     mutable OwningPtr<APIMisuse> BT;
98 
99     void warnIfNilExpr(const Expr *E,
100                        const char *Msg,
101                        CheckerContext &C) const;
102 
103     void warnIfNilArg(CheckerContext &C,
104                       const ObjCMethodCall &msg, unsigned Arg,
105                       FoundationClass Class,
106                       bool CanBeSubscript = false) const;
107 
108     void generateBugReport(ExplodedNode *N,
109                            StringRef Msg,
110                            SourceRange Range,
111                            const Expr *Expr,
112                            CheckerContext &C) const;
113 
114   public:
115     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
116     void checkPostStmt(const ObjCDictionaryLiteral *DL,
117                        CheckerContext &C) const;
118     void checkPostStmt(const ObjCArrayLiteral *AL,
119                        CheckerContext &C) const;
120   };
121 }
122 
123 void NilArgChecker::warnIfNilExpr(const Expr *E,
124                                   const char *Msg,
125                                   CheckerContext &C) const {
126   ProgramStateRef State = C.getState();
127   if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
128 
129     if (ExplodedNode *N = C.generateSink()) {
130       generateBugReport(N, Msg, E->getSourceRange(), E, C);
131     }
132 
133   }
134 }
135 
136 void NilArgChecker::warnIfNilArg(CheckerContext &C,
137                                  const ObjCMethodCall &msg,
138                                  unsigned int Arg,
139                                  FoundationClass Class,
140                                  bool CanBeSubscript) const {
141   // Check if the argument is nil.
142   ProgramStateRef State = C.getState();
143   if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
144       return;
145 
146   if (ExplodedNode *N = C.generateSink()) {
147     SmallString<128> sbuf;
148     llvm::raw_svector_ostream os(sbuf);
149 
150     if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
151 
152       if (Class == FC_NSArray) {
153         os << "Array element cannot be nil";
154       } else if (Class == FC_NSDictionary) {
155         if (Arg == 0) {
156           os << "Value stored into '";
157           os << GetReceiverInterfaceName(msg) << "' cannot be nil";
158         } else {
159           assert(Arg == 1);
160           os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
161         }
162       } else
163         llvm_unreachable("Missing foundation class for the subscript expr");
164 
165     } else {
166       if (Class == FC_NSDictionary) {
167         if (Arg == 0)
168           os << "Value argument ";
169         else {
170           assert(Arg == 1);
171           os << "Key argument ";
172         }
173         os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
174       } else {
175         os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
176         << msg.getSelector().getAsString() << "' cannot be nil";
177       }
178     }
179 
180     generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
181                       msg.getArgExpr(Arg), C);
182   }
183 }
184 
185 void NilArgChecker::generateBugReport(ExplodedNode *N,
186                                       StringRef Msg,
187                                       SourceRange Range,
188                                       const Expr *E,
189                                       CheckerContext &C) const {
190   if (!BT)
191     BT.reset(new APIMisuse("nil argument"));
192 
193   BugReport *R = new BugReport(*BT, Msg, N);
194   R->addRange(Range);
195   bugreporter::trackNullOrUndefValue(N, E, *R);
196   C.emitReport(R);
197 }
198 
199 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
200                                         CheckerContext &C) const {
201   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
202   if (!ID)
203     return;
204 
205   FoundationClass Class = findKnownClass(ID);
206 
207   static const unsigned InvalidArgIndex = UINT_MAX;
208   unsigned Arg = InvalidArgIndex;
209   bool CanBeSubscript = false;
210 
211   if (Class == FC_NSString) {
212     Selector S = msg.getSelector();
213 
214     if (S.isUnarySelector())
215       return;
216 
217     // FIXME: This is going to be really slow doing these checks with
218     //  lexical comparisons.
219 
220     std::string NameStr = S.getAsString();
221     StringRef Name(NameStr);
222     assert(!Name.empty());
223 
224     // FIXME: Checking for initWithFormat: will not work in most cases
225     //  yet because [NSString alloc] returns id, not NSString*.  We will
226     //  need support for tracking expected-type information in the analyzer
227     //  to find these errors.
228     if (Name == "caseInsensitiveCompare:" ||
229         Name == "compare:" ||
230         Name == "compare:options:" ||
231         Name == "compare:options:range:" ||
232         Name == "compare:options:range:locale:" ||
233         Name == "componentsSeparatedByCharactersInSet:" ||
234         Name == "initWithFormat:") {
235       Arg = 0;
236     }
237   } else if (Class == FC_NSArray) {
238     Selector S = msg.getSelector();
239 
240     if (S.isUnarySelector())
241       return;
242 
243     if (S.getNameForSlot(0).equals("addObject")) {
244       Arg = 0;
245     } else if (S.getNameForSlot(0).equals("insertObject") &&
246                S.getNameForSlot(1).equals("atIndex")) {
247       Arg = 0;
248     } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
249                S.getNameForSlot(1).equals("withObject")) {
250       Arg = 1;
251     } else if (S.getNameForSlot(0).equals("setObject") &&
252                S.getNameForSlot(1).equals("atIndexedSubscript")) {
253       Arg = 0;
254       CanBeSubscript = true;
255     } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
256       Arg = 0;
257     }
258   } else if (Class == FC_NSDictionary) {
259     Selector S = msg.getSelector();
260 
261     if (S.isUnarySelector())
262       return;
263 
264     if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
265         S.getNameForSlot(1).equals("forKey")) {
266       Arg = 0;
267       warnIfNilArg(C, msg, /* Arg */1, Class);
268     } else if (S.getNameForSlot(0).equals("setObject") &&
269                S.getNameForSlot(1).equals("forKey")) {
270       Arg = 0;
271       warnIfNilArg(C, msg, /* Arg */1, Class);
272     } else if (S.getNameForSlot(0).equals("setObject") &&
273                S.getNameForSlot(1).equals("forKeyedSubscript")) {
274       CanBeSubscript = true;
275       Arg = 0;
276       warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
277     } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
278       Arg = 0;
279     }
280   }
281 
282   // If argument is '0', report a warning.
283   if ((Arg != InvalidArgIndex))
284     warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
285 
286 }
287 
288 void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
289                                   CheckerContext &C) const {
290   unsigned NumOfElements = AL->getNumElements();
291   for (unsigned i = 0; i < NumOfElements; ++i) {
292     warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
293   }
294 }
295 
296 void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
297                                   CheckerContext &C) const {
298   unsigned NumOfElements = DL->getNumElements();
299   for (unsigned i = 0; i < NumOfElements; ++i) {
300     ObjCDictionaryElement Element = DL->getKeyValueElement(i);
301     warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
302     warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
303   }
304 }
305 
306 //===----------------------------------------------------------------------===//
307 // Error reporting.
308 //===----------------------------------------------------------------------===//
309 
310 namespace {
311 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
312   mutable OwningPtr<APIMisuse> BT;
313   mutable IdentifierInfo* II;
314 public:
315   CFNumberCreateChecker() : II(0) {}
316 
317   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
318 
319 private:
320   void EmitError(const TypedRegion* R, const Expr *Ex,
321                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
322 };
323 } // end anonymous namespace
324 
325 enum CFNumberType {
326   kCFNumberSInt8Type = 1,
327   kCFNumberSInt16Type = 2,
328   kCFNumberSInt32Type = 3,
329   kCFNumberSInt64Type = 4,
330   kCFNumberFloat32Type = 5,
331   kCFNumberFloat64Type = 6,
332   kCFNumberCharType = 7,
333   kCFNumberShortType = 8,
334   kCFNumberIntType = 9,
335   kCFNumberLongType = 10,
336   kCFNumberLongLongType = 11,
337   kCFNumberFloatType = 12,
338   kCFNumberDoubleType = 13,
339   kCFNumberCFIndexType = 14,
340   kCFNumberNSIntegerType = 15,
341   kCFNumberCGFloatType = 16
342 };
343 
344 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
345   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
346 
347   if (i < kCFNumberCharType)
348     return FixedSize[i-1];
349 
350   QualType T;
351 
352   switch (i) {
353     case kCFNumberCharType:     T = Ctx.CharTy;     break;
354     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
355     case kCFNumberIntType:      T = Ctx.IntTy;      break;
356     case kCFNumberLongType:     T = Ctx.LongTy;     break;
357     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
358     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
359     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
360     case kCFNumberCFIndexType:
361     case kCFNumberNSIntegerType:
362     case kCFNumberCGFloatType:
363       // FIXME: We need a way to map from names to Type*.
364     default:
365       return None;
366   }
367 
368   return Ctx.getTypeSize(T);
369 }
370 
371 #if 0
372 static const char* GetCFNumberTypeStr(uint64_t i) {
373   static const char* Names[] = {
374     "kCFNumberSInt8Type",
375     "kCFNumberSInt16Type",
376     "kCFNumberSInt32Type",
377     "kCFNumberSInt64Type",
378     "kCFNumberFloat32Type",
379     "kCFNumberFloat64Type",
380     "kCFNumberCharType",
381     "kCFNumberShortType",
382     "kCFNumberIntType",
383     "kCFNumberLongType",
384     "kCFNumberLongLongType",
385     "kCFNumberFloatType",
386     "kCFNumberDoubleType",
387     "kCFNumberCFIndexType",
388     "kCFNumberNSIntegerType",
389     "kCFNumberCGFloatType"
390   };
391 
392   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
393 }
394 #endif
395 
396 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
397                                          CheckerContext &C) const {
398   ProgramStateRef state = C.getState();
399   const FunctionDecl *FD = C.getCalleeDecl(CE);
400   if (!FD)
401     return;
402 
403   ASTContext &Ctx = C.getASTContext();
404   if (!II)
405     II = &Ctx.Idents.get("CFNumberCreate");
406 
407   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
408     return;
409 
410   // Get the value of the "theType" argument.
411   const LocationContext *LCtx = C.getLocationContext();
412   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
413 
414   // FIXME: We really should allow ranges of valid theType values, and
415   //   bifurcate the state appropriately.
416   Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
417   if (!V)
418     return;
419 
420   uint64_t NumberKind = V->getValue().getLimitedValue();
421   Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
422 
423   // FIXME: In some cases we can emit an error.
424   if (!OptTargetSize)
425     return;
426 
427   uint64_t TargetSize = *OptTargetSize;
428 
429   // Look at the value of the integer being passed by reference.  Essentially
430   // we want to catch cases where the value passed in is not equal to the
431   // size of the type being created.
432   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
433 
434   // FIXME: Eventually we should handle arbitrary locations.  We can do this
435   //  by having an enhanced memory model that does low-level typing.
436   Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
437   if (!LV)
438     return;
439 
440   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
441   if (!R)
442     return;
443 
444   QualType T = Ctx.getCanonicalType(R->getValueType());
445 
446   // FIXME: If the pointee isn't an integer type, should we flag a warning?
447   //  People can do weird stuff with pointers.
448 
449   if (!T->isIntegralOrEnumerationType())
450     return;
451 
452   uint64_t SourceSize = Ctx.getTypeSize(T);
453 
454   // CHECK: is SourceSize == TargetSize
455   if (SourceSize == TargetSize)
456     return;
457 
458   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
459   // otherwise generate a regular node.
460   //
461   // FIXME: We can actually create an abstract "CFNumber" object that has
462   //  the bits initialized to the provided values.
463   //
464   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
465                                                 : C.addTransition()) {
466     SmallString<128> sbuf;
467     llvm::raw_svector_ostream os(sbuf);
468 
469     os << (SourceSize == 8 ? "An " : "A ")
470        << SourceSize << " bit integer is used to initialize a CFNumber "
471                         "object that represents "
472        << (TargetSize == 8 ? "an " : "a ")
473        << TargetSize << " bit integer. ";
474 
475     if (SourceSize < TargetSize)
476       os << (TargetSize - SourceSize)
477       << " bits of the CFNumber value will be garbage." ;
478     else
479       os << (SourceSize - TargetSize)
480       << " bits of the input integer will be lost.";
481 
482     if (!BT)
483       BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
484 
485     BugReport *report = new BugReport(*BT, os.str(), N);
486     report->addRange(CE->getArg(2)->getSourceRange());
487     C.emitReport(report);
488   }
489 }
490 
491 //===----------------------------------------------------------------------===//
492 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
493 //===----------------------------------------------------------------------===//
494 
495 namespace {
496 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
497   mutable OwningPtr<APIMisuse> BT;
498   mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
499 public:
500   CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
501   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
502 };
503 } // end anonymous namespace
504 
505 
506 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
507                                           CheckerContext &C) const {
508   // If the CallExpr doesn't have exactly 1 argument just give up checking.
509   if (CE->getNumArgs() != 1)
510     return;
511 
512   ProgramStateRef state = C.getState();
513   const FunctionDecl *FD = C.getCalleeDecl(CE);
514   if (!FD)
515     return;
516 
517   if (!BT) {
518     ASTContext &Ctx = C.getASTContext();
519     Retain = &Ctx.Idents.get("CFRetain");
520     Release = &Ctx.Idents.get("CFRelease");
521     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
522     BT.reset(
523       new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
524   }
525 
526   // Check if we called CFRetain/CFRelease/CFMakeCollectable.
527   const IdentifierInfo *FuncII = FD->getIdentifier();
528   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
529     return;
530 
531   // FIXME: The rest of this just checks that the argument is non-null.
532   // It should probably be refactored and combined with NonNullParamChecker.
533 
534   // Get the argument's value.
535   const Expr *Arg = CE->getArg(0);
536   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
537   Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
538   if (!DefArgVal)
539     return;
540 
541   // Get a NULL value.
542   SValBuilder &svalBuilder = C.getSValBuilder();
543   DefinedSVal zero =
544       svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
545 
546   // Make an expression asserting that they're equal.
547   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
548 
549   // Are they equal?
550   ProgramStateRef stateTrue, stateFalse;
551   llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
552 
553   if (stateTrue && !stateFalse) {
554     ExplodedNode *N = C.generateSink(stateTrue);
555     if (!N)
556       return;
557 
558     const char *description;
559     if (FuncII == Retain)
560       description = "Null pointer argument in call to CFRetain";
561     else if (FuncII == Release)
562       description = "Null pointer argument in call to CFRelease";
563     else if (FuncII == MakeCollectable)
564       description = "Null pointer argument in call to CFMakeCollectable";
565     else
566       llvm_unreachable("impossible case");
567 
568     BugReport *report = new BugReport(*BT, description, N);
569     report->addRange(Arg->getSourceRange());
570     bugreporter::trackNullOrUndefValue(N, Arg, *report);
571     C.emitReport(report);
572     return;
573   }
574 
575   // From here on, we know the argument is non-null.
576   C.addTransition(stateFalse);
577 }
578 
579 //===----------------------------------------------------------------------===//
580 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
581 //===----------------------------------------------------------------------===//
582 
583 namespace {
584 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
585   mutable Selector releaseS;
586   mutable Selector retainS;
587   mutable Selector autoreleaseS;
588   mutable Selector drainS;
589   mutable OwningPtr<BugType> BT;
590 
591 public:
592   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
593 };
594 }
595 
596 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
597                                               CheckerContext &C) const {
598 
599   if (!BT) {
600     BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
601                            "instance"));
602 
603     ASTContext &Ctx = C.getASTContext();
604     releaseS = GetNullarySelector("release", Ctx);
605     retainS = GetNullarySelector("retain", Ctx);
606     autoreleaseS = GetNullarySelector("autorelease", Ctx);
607     drainS = GetNullarySelector("drain", Ctx);
608   }
609 
610   if (msg.isInstanceMessage())
611     return;
612   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
613   assert(Class);
614 
615   Selector S = msg.getSelector();
616   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
617     return;
618 
619   if (ExplodedNode *N = C.addTransition()) {
620     SmallString<200> buf;
621     llvm::raw_svector_ostream os(buf);
622 
623     os << "The '" << S.getAsString() << "' message should be sent to instances "
624           "of class '" << Class->getName()
625        << "' and not the class directly";
626 
627     BugReport *report = new BugReport(*BT, os.str(), N);
628     report->addRange(msg.getSourceRange());
629     C.emitReport(report);
630   }
631 }
632 
633 //===----------------------------------------------------------------------===//
634 // Check for passing non-Objective-C types to variadic methods that expect
635 // only Objective-C types.
636 //===----------------------------------------------------------------------===//
637 
638 namespace {
639 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
640   mutable Selector arrayWithObjectsS;
641   mutable Selector dictionaryWithObjectsAndKeysS;
642   mutable Selector setWithObjectsS;
643   mutable Selector orderedSetWithObjectsS;
644   mutable Selector initWithObjectsS;
645   mutable Selector initWithObjectsAndKeysS;
646   mutable OwningPtr<BugType> BT;
647 
648   bool isVariadicMessage(const ObjCMethodCall &msg) const;
649 
650 public:
651   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
652 };
653 }
654 
655 /// isVariadicMessage - Returns whether the given message is a variadic message,
656 /// where all arguments must be Objective-C types.
657 bool
658 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
659   const ObjCMethodDecl *MD = msg.getDecl();
660 
661   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
662     return false;
663 
664   Selector S = msg.getSelector();
665 
666   if (msg.isInstanceMessage()) {
667     // FIXME: Ideally we'd look at the receiver interface here, but that's not
668     // useful for init, because alloc returns 'id'. In theory, this could lead
669     // to false positives, for example if there existed a class that had an
670     // initWithObjects: implementation that does accept non-Objective-C pointer
671     // types, but the chance of that happening is pretty small compared to the
672     // gains that this analysis gives.
673     const ObjCInterfaceDecl *Class = MD->getClassInterface();
674 
675     switch (findKnownClass(Class)) {
676     case FC_NSArray:
677     case FC_NSOrderedSet:
678     case FC_NSSet:
679       return S == initWithObjectsS;
680     case FC_NSDictionary:
681       return S == initWithObjectsAndKeysS;
682     default:
683       return false;
684     }
685   } else {
686     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
687 
688     switch (findKnownClass(Class)) {
689       case FC_NSArray:
690         return S == arrayWithObjectsS;
691       case FC_NSOrderedSet:
692         return S == orderedSetWithObjectsS;
693       case FC_NSSet:
694         return S == setWithObjectsS;
695       case FC_NSDictionary:
696         return S == dictionaryWithObjectsAndKeysS;
697       default:
698         return false;
699     }
700   }
701 }
702 
703 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
704                                                     CheckerContext &C) const {
705   if (!BT) {
706     BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
707                            "Objective-C pointer types"));
708 
709     ASTContext &Ctx = C.getASTContext();
710     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
711     dictionaryWithObjectsAndKeysS =
712       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
713     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
714     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
715 
716     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
717     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
718   }
719 
720   if (!isVariadicMessage(msg))
721       return;
722 
723   // We are not interested in the selector arguments since they have
724   // well-defined types, so the compiler will issue a warning for them.
725   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
726 
727   // We're not interested in the last argument since it has to be nil or the
728   // compiler would have issued a warning for it elsewhere.
729   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
730 
731   if (variadicArgsEnd <= variadicArgsBegin)
732     return;
733 
734   // Verify that all arguments have Objective-C types.
735   Optional<ExplodedNode*> errorNode;
736 
737   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
738     QualType ArgTy = msg.getArgExpr(I)->getType();
739     if (ArgTy->isObjCObjectPointerType())
740       continue;
741 
742     // Block pointers are treaded as Objective-C pointers.
743     if (ArgTy->isBlockPointerType())
744       continue;
745 
746     // Ignore pointer constants.
747     if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
748       continue;
749 
750     // Ignore pointer types annotated with 'NSObject' attribute.
751     if (C.getASTContext().isObjCNSObjectType(ArgTy))
752       continue;
753 
754     // Ignore CF references, which can be toll-free bridged.
755     if (coreFoundation::isCFObjectRef(ArgTy))
756       continue;
757 
758     // Generate only one error node to use for all bug reports.
759     if (!errorNode.hasValue())
760       errorNode = C.addTransition();
761 
762     if (!errorNode.getValue())
763       continue;
764 
765     SmallString<128> sbuf;
766     llvm::raw_svector_ostream os(sbuf);
767 
768     StringRef TypeName = GetReceiverInterfaceName(msg);
769     if (!TypeName.empty())
770       os << "Argument to '" << TypeName << "' method '";
771     else
772       os << "Argument to method '";
773 
774     os << msg.getSelector().getAsString()
775        << "' should be an Objective-C pointer type, not '";
776     ArgTy.print(os, C.getLangOpts());
777     os << "'";
778 
779     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
780     R->addRange(msg.getArgSourceRange(I));
781     C.emitReport(R);
782   }
783 }
784 
785 //===----------------------------------------------------------------------===//
786 // Improves the modeling of loops over Cocoa collections.
787 //===----------------------------------------------------------------------===//
788 
789 // The map from container symbol to the container count symbol.
790 // We currently will remember the last countainer count symbol encountered.
791 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
792 REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
793 
794 namespace {
795 class ObjCLoopChecker
796   : public Checker<check::PostStmt<ObjCForCollectionStmt>,
797                    check::PostObjCMessage,
798                    check::DeadSymbols,
799                    check::PointerEscape > {
800   mutable IdentifierInfo *CountSelectorII;
801 
802   bool isCollectionCountMethod(const ObjCMethodCall &M,
803                                CheckerContext &C) const;
804 
805 public:
806   ObjCLoopChecker() : CountSelectorII(0) {}
807   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
808   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
809   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
810   ProgramStateRef checkPointerEscape(ProgramStateRef State,
811                                      const InvalidatedSymbols &Escaped,
812                                      const CallEvent *Call,
813                                      PointerEscapeKind Kind) const;
814 };
815 }
816 
817 static bool isKnownNonNilCollectionType(QualType T) {
818   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
819   if (!PT)
820     return false;
821 
822   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
823   if (!ID)
824     return false;
825 
826   switch (findKnownClass(ID)) {
827   case FC_NSArray:
828   case FC_NSDictionary:
829   case FC_NSEnumerator:
830   case FC_NSOrderedSet:
831   case FC_NSSet:
832     return true;
833   default:
834     return false;
835   }
836 }
837 
838 /// Assumes that the collection is non-nil.
839 ///
840 /// If the collection is known to be nil, returns NULL to indicate an infeasible
841 /// path.
842 static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
843                                              ProgramStateRef State,
844                                              const ObjCForCollectionStmt *FCS) {
845   if (!State)
846     return NULL;
847 
848   SVal CollectionVal = C.getSVal(FCS->getCollection());
849   Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
850   if (!KnownCollection)
851     return State;
852 
853   ProgramStateRef StNonNil, StNil;
854   llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
855   if (StNil && !StNonNil) {
856     // The collection is nil. This path is infeasible.
857     return NULL;
858   }
859 
860   return StNonNil;
861 }
862 
863 /// Assumes that the collection elements are non-nil.
864 ///
865 /// This only applies if the collection is one of those known not to contain
866 /// nil values.
867 static ProgramStateRef checkElementNonNil(CheckerContext &C,
868                                           ProgramStateRef State,
869                                           const ObjCForCollectionStmt *FCS) {
870   if (!State)
871     return NULL;
872 
873   // See if the collection is one where we /know/ the elements are non-nil.
874   if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
875     return State;
876 
877   const LocationContext *LCtx = C.getLocationContext();
878   const Stmt *Element = FCS->getElement();
879 
880   // FIXME: Copied from ExprEngineObjC.
881   Optional<Loc> ElementLoc;
882   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
883     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
884     assert(ElemDecl->getInit() == 0);
885     ElementLoc = State->getLValue(ElemDecl, LCtx);
886   } else {
887     ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
888   }
889 
890   if (!ElementLoc)
891     return State;
892 
893   // Go ahead and assume the value is non-nil.
894   SVal Val = State->getSVal(*ElementLoc);
895   return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
896 }
897 
898 /// Returns NULL state if the collection is known to contain elements
899 /// (or is known not to contain elements if the Assumption parameter is false.)
900 static ProgramStateRef
901 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
902                          SymbolRef CollectionS, bool Assumption) {
903   if (!State || !CollectionS)
904     return State;
905 
906   const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
907   if (!CountS) {
908     const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
909     if (!KnownNonEmpty)
910       return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
911     return (Assumption == *KnownNonEmpty) ? State : NULL;
912   }
913 
914   SValBuilder &SvalBuilder = C.getSValBuilder();
915   SVal CountGreaterThanZeroVal =
916     SvalBuilder.evalBinOp(State, BO_GT,
917                           nonloc::SymbolVal(*CountS),
918                           SvalBuilder.makeIntVal(0, (*CountS)->getType()),
919                           SvalBuilder.getConditionType());
920   Optional<DefinedSVal> CountGreaterThanZero =
921     CountGreaterThanZeroVal.getAs<DefinedSVal>();
922   if (!CountGreaterThanZero) {
923     // The SValBuilder cannot construct a valid SVal for this condition.
924     // This means we cannot properly reason about it.
925     return State;
926   }
927 
928   return State->assume(*CountGreaterThanZero, Assumption);
929 }
930 
931 static ProgramStateRef
932 assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
933                          const ObjCForCollectionStmt *FCS,
934                          bool Assumption) {
935   if (!State)
936     return NULL;
937 
938   SymbolRef CollectionS =
939     State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
940   return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
941 }
942 
943 
944 /// If the fist block edge is a back edge, we are reentering the loop.
945 static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
946                                              const ObjCForCollectionStmt *FCS) {
947   if (!N)
948     return false;
949 
950   ProgramPoint P = N->getLocation();
951   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
952     if (BE->getSrc()->getLoopTarget() == FCS)
953       return true;
954     return false;
955   }
956 
957   // Keep looking for a block edge.
958   for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
959                                          E = N->pred_end(); I != E; ++I) {
960     if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
961       return true;
962   }
963 
964   return false;
965 }
966 
967 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
968                                     CheckerContext &C) const {
969   ProgramStateRef State = C.getState();
970 
971   // Check if this is the branch for the end of the loop.
972   SVal CollectionSentinel = C.getSVal(FCS);
973   if (CollectionSentinel.isZeroConstant()) {
974     if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
975       State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
976 
977   // Otherwise, this is a branch that goes through the loop body.
978   } else {
979     State = checkCollectionNonNil(C, State, FCS);
980     State = checkElementNonNil(C, State, FCS);
981     State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
982   }
983 
984   if (!State)
985     C.generateSink();
986   else if (State != C.getState())
987     C.addTransition(State);
988 }
989 
990 bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
991                                               CheckerContext &C) const {
992   Selector S = M.getSelector();
993   // Initialize the identifiers on first use.
994   if (!CountSelectorII)
995     CountSelectorII = &C.getASTContext().Idents.get("count");
996 
997   // If the method returns collection count, record the value.
998   if (S.isUnarySelector() &&
999       (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1000     return true;
1001 
1002   return false;
1003 }
1004 
1005 void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1006                                            CheckerContext &C) const {
1007   if (!M.isInstanceMessage())
1008     return;
1009 
1010   const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1011   if (!ClassID)
1012     return;
1013 
1014   FoundationClass Class = findKnownClass(ClassID);
1015   if (Class != FC_NSDictionary &&
1016       Class != FC_NSArray &&
1017       Class != FC_NSSet &&
1018       Class != FC_NSOrderedSet)
1019     return;
1020 
1021   SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1022   if (!ContainerS)
1023     return;
1024 
1025   // If we are processing a call to "count", get the symbolic value returned by
1026   // a call to "count" and add it to the map.
1027   if (!isCollectionCountMethod(M, C))
1028     return;
1029 
1030   const Expr *MsgExpr = M.getOriginExpr();
1031   SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1032   if (CountS) {
1033     ProgramStateRef State = C.getState();
1034 
1035     C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1036     State = State->set<ContainerCountMap>(ContainerS, CountS);
1037 
1038     if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1039       State = State->remove<ContainerNonEmptyMap>(ContainerS);
1040       State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1041     }
1042 
1043     C.addTransition(State);
1044   }
1045   return;
1046 }
1047 
1048 static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1049   const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1050   if (!Message)
1051     return 0;
1052 
1053   const ObjCMethodDecl *MD = Message->getDecl();
1054   if (!MD)
1055     return 0;
1056 
1057   const ObjCInterfaceDecl *StaticClass;
1058   if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1059     // We can't find out where the method was declared without doing more work.
1060     // Instead, see if the receiver is statically typed as a known immutable
1061     // collection.
1062     StaticClass = Message->getOriginExpr()->getReceiverInterface();
1063   } else {
1064     StaticClass = MD->getClassInterface();
1065   }
1066 
1067   if (!StaticClass)
1068     return 0;
1069 
1070   switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1071   case FC_None:
1072     return 0;
1073   case FC_NSArray:
1074   case FC_NSDictionary:
1075   case FC_NSEnumerator:
1076   case FC_NSNull:
1077   case FC_NSOrderedSet:
1078   case FC_NSSet:
1079   case FC_NSString:
1080     break;
1081   }
1082 
1083   return Message->getReceiverSVal().getAsSymbol();
1084 }
1085 
1086 ProgramStateRef
1087 ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1088                                     const InvalidatedSymbols &Escaped,
1089                                     const CallEvent *Call,
1090                                     PointerEscapeKind Kind) const {
1091   SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1092 
1093   // Remove the invalidated symbols form the collection count map.
1094   for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1095        E = Escaped.end();
1096        I != E; ++I) {
1097     SymbolRef Sym = *I;
1098 
1099     // Don't invalidate this symbol's count if we know the method being called
1100     // is declared on an immutable class. This isn't completely correct if the
1101     // receiver is also passed as an argument, but in most uses of NSArray,
1102     // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1103     if (Sym == ImmutableReceiver)
1104       continue;
1105 
1106     // The symbol escaped. Pessimistically, assume that the count could have
1107     // changed.
1108     State = State->remove<ContainerCountMap>(Sym);
1109     State = State->remove<ContainerNonEmptyMap>(Sym);
1110   }
1111   return State;
1112 }
1113 
1114 void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1115                                        CheckerContext &C) const {
1116   ProgramStateRef State = C.getState();
1117 
1118   // Remove the dead symbols from the collection count map.
1119   ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1120   for (ContainerCountMapTy::iterator I = Tracked.begin(),
1121                                      E = Tracked.end(); I != E; ++I) {
1122     SymbolRef Sym = I->first;
1123     if (SymReaper.isDead(Sym)) {
1124       State = State->remove<ContainerCountMap>(Sym);
1125       State = State->remove<ContainerNonEmptyMap>(Sym);
1126     }
1127   }
1128 
1129   C.addTransition(State);
1130 }
1131 
1132 namespace {
1133 /// \class ObjCNonNilReturnValueChecker
1134 /// \brief The checker restricts the return values of APIs known to
1135 /// never (or almost never) return 'nil'.
1136 class ObjCNonNilReturnValueChecker
1137   : public Checker<check::PostObjCMessage> {
1138     mutable bool Initialized;
1139     mutable Selector ObjectAtIndex;
1140     mutable Selector ObjectAtIndexedSubscript;
1141     mutable Selector NullSelector;
1142 
1143 public:
1144   ObjCNonNilReturnValueChecker() : Initialized(false) {}
1145   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1146 };
1147 }
1148 
1149 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1150                                            ProgramStateRef State,
1151                                            CheckerContext &C) {
1152   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1153   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1154     return State->assume(*DV, true);
1155   return State;
1156 }
1157 
1158 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1159                                                         CheckerContext &C)
1160                                                         const {
1161   ProgramStateRef State = C.getState();
1162 
1163   if (!Initialized) {
1164     ASTContext &Ctx = C.getASTContext();
1165     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1166     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1167     NullSelector = GetNullarySelector("null", Ctx);
1168   }
1169 
1170   // Check the receiver type.
1171   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1172 
1173     // Assume that object returned from '[self init]' or '[super init]' is not
1174     // 'nil' if we are processing an inlined function/method.
1175     //
1176     // A defensive callee will (and should) check if the object returned by
1177     // '[super init]' is 'nil' before doing it's own initialization. However,
1178     // since 'nil' is rarely returned in practice, we should not warn when the
1179     // caller to the defensive constructor uses the object in contexts where
1180     // 'nil' is not accepted.
1181     if (!C.inTopFrame() && M.getDecl() &&
1182         M.getDecl()->getMethodFamily() == OMF_init &&
1183         M.isReceiverSelfOrSuper()) {
1184       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1185     }
1186 
1187     FoundationClass Cl = findKnownClass(Interface);
1188 
1189     // Objects returned from
1190     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1191     // are never 'nil'.
1192     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1193       Selector Sel = M.getSelector();
1194       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1195         // Go ahead and assume the value is non-nil.
1196         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1197       }
1198     }
1199 
1200     // Objects returned from [NSNull null] are not nil.
1201     if (Cl == FC_NSNull) {
1202       if (M.getSelector() == NullSelector) {
1203         // Go ahead and assume the value is non-nil.
1204         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1205       }
1206     }
1207   }
1208   C.addTransition(State);
1209 }
1210 
1211 //===----------------------------------------------------------------------===//
1212 // Check registration.
1213 //===----------------------------------------------------------------------===//
1214 
1215 void ento::registerNilArgChecker(CheckerManager &mgr) {
1216   mgr.registerChecker<NilArgChecker>();
1217 }
1218 
1219 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
1220   mgr.registerChecker<CFNumberCreateChecker>();
1221 }
1222 
1223 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1224   mgr.registerChecker<CFRetainReleaseChecker>();
1225 }
1226 
1227 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1228   mgr.registerChecker<ClassReleaseChecker>();
1229 }
1230 
1231 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1232   mgr.registerChecker<VariadicMethodTypeChecker>();
1233 }
1234 
1235 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1236   mgr.registerChecker<ObjCLoopChecker>();
1237 }
1238 
1239 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1240   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1241 }
1242