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