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