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