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