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