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.generateErrorNode()) {
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.generateErrorNode()) {
161    SmallString<128> sbuf;
162    llvm::raw_svector_ostream os(sbuf);
163
164    if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
165
166      if (Class == FC_NSArray) {
167        os << "Array element cannot be nil";
168      } else if (Class == FC_NSDictionary) {
169        if (Arg == 0) {
170          os << "Value stored into '";
171          os << GetReceiverInterfaceName(msg) << "' cannot be nil";
172        } else {
173          assert(Arg == 1);
174          os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
175        }
176      } else
177        llvm_unreachable("Missing foundation class for the subscript expr");
178
179    } else {
180      if (Class == FC_NSDictionary) {
181        if (Arg == 0)
182          os << "Value argument ";
183        else {
184          assert(Arg == 1);
185          os << "Key argument ";
186        }
187        os << "to '";
188        msg.getSelector().print(os);
189        os << "' cannot be nil";
190      } else {
191        os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
192        msg.getSelector().print(os);
193        os << "' cannot be nil";
194      }
195    }
196
197    generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
198                      msg.getArgExpr(Arg), C);
199  }
200}
201
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  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
211  R->addRange(Range);
212  bugreporter::trackNullOrUndefValue(N, E, *R);
213  C.emitReport(std::move(R));
214}
215
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 = 1;
311    } else if (S == RemoveObjectForKeySel) {
312      Arg = 0;
313    }
314  }
315
316  // If argument is '0', report a warning.
317  if ((Arg != InvalidArgIndex))
318    warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
319}
320
321void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
322                                  CheckerContext &C) const {
323  unsigned NumOfElements = AL->getNumElements();
324  for (unsigned i = 0; i < NumOfElements; ++i) {
325    warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
326  }
327}
328
329void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
330                                  CheckerContext &C) const {
331  unsigned NumOfElements = DL->getNumElements();
332  for (unsigned i = 0; i < NumOfElements; ++i) {
333    ObjCDictionaryElement Element = DL->getKeyValueElement(i);
334    warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
335    warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
336  }
337}
338
339//===----------------------------------------------------------------------===//
340// Error reporting.
341//===----------------------------------------------------------------------===//
342
343namespace {
344class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
345  mutable std::unique_ptr<APIMisuse> BT;
346  mutable IdentifierInfo* II;
347public:
348  CFNumberCreateChecker() : II(nullptr) {}
349
350  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
351
352private:
353  void EmitError(const TypedRegion* R, const Expr *Ex,
354                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
355};
356} // end anonymous namespace
357
358enum CFNumberType {
359  kCFNumberSInt8Type = 1,
360  kCFNumberSInt16Type = 2,
361  kCFNumberSInt32Type = 3,
362  kCFNumberSInt64Type = 4,
363  kCFNumberFloat32Type = 5,
364  kCFNumberFloat64Type = 6,
365  kCFNumberCharType = 7,
366  kCFNumberShortType = 8,
367  kCFNumberIntType = 9,
368  kCFNumberLongType = 10,
369  kCFNumberLongLongType = 11,
370  kCFNumberFloatType = 12,
371  kCFNumberDoubleType = 13,
372  kCFNumberCFIndexType = 14,
373  kCFNumberNSIntegerType = 15,
374  kCFNumberCGFloatType = 16
375};
376
377static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
378  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
379
380  if (i < kCFNumberCharType)
381    return FixedSize[i-1];
382
383  QualType T;
384
385  switch (i) {
386    case kCFNumberCharType:     T = Ctx.CharTy;     break;
387    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
388    case kCFNumberIntType:      T = Ctx.IntTy;      break;
389    case kCFNumberLongType:     T = Ctx.LongTy;     break;
390    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
391    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
392    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
393    case kCFNumberCFIndexType:
394    case kCFNumberNSIntegerType:
395    case kCFNumberCGFloatType:
396      // FIXME: We need a way to map from names to Type*.
397    default:
398      return None;
399  }
400
401  return Ctx.getTypeSize(T);
402}
403
404#if 0
405static const char* GetCFNumberTypeStr(uint64_t i) {
406  static const char* Names[] = {
407    "kCFNumberSInt8Type",
408    "kCFNumberSInt16Type",
409    "kCFNumberSInt32Type",
410    "kCFNumberSInt64Type",
411    "kCFNumberFloat32Type",
412    "kCFNumberFloat64Type",
413    "kCFNumberCharType",
414    "kCFNumberShortType",
415    "kCFNumberIntType",
416    "kCFNumberLongType",
417    "kCFNumberLongLongType",
418    "kCFNumberFloatType",
419    "kCFNumberDoubleType",
420    "kCFNumberCFIndexType",
421    "kCFNumberNSIntegerType",
422    "kCFNumberCGFloatType"
423  };
424
425  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
426}
427#endif
428
429void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
430                                         CheckerContext &C) const {
431  ProgramStateRef state = C.getState();
432  const FunctionDecl *FD = C.getCalleeDecl(CE);
433  if (!FD)
434    return;
435
436  ASTContext &Ctx = C.getASTContext();
437  if (!II)
438    II = &Ctx.Idents.get("CFNumberCreate");
439
440  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
441    return;
442
443  // Get the value of the "theType" argument.
444  const LocationContext *LCtx = C.getLocationContext();
445  SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
446
447  // FIXME: We really should allow ranges of valid theType values, and
448  //   bifurcate the state appropriately.
449  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
450  if (!V)
451    return;
452
453  uint64_t NumberKind = V->getValue().getLimitedValue();
454  Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
455
456  // FIXME: In some cases we can emit an error.
457  if (!OptTargetSize)
458    return;
459
460  uint64_t TargetSize = *OptTargetSize;
461
462  // Look at the value of the integer being passed by reference.  Essentially
463  // we want to catch cases where the value passed in is not equal to the
464  // size of the type being created.
465  SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
466
467  // FIXME: Eventually we should handle arbitrary locations.  We can do this
468  //  by having an enhanced memory model that does low-level typing.
469  Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
470  if (!LV)
471    return;
472
473  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
474  if (!R)
475    return;
476
477  QualType T = Ctx.getCanonicalType(R->getValueType());
478
479  // FIXME: If the pointee isn't an integer type, should we flag a warning?
480  //  People can do weird stuff with pointers.
481
482  if (!T->isIntegralOrEnumerationType())
483    return;
484
485  uint64_t SourceSize = Ctx.getTypeSize(T);
486
487  // CHECK: is SourceSize == TargetSize
488  if (SourceSize == TargetSize)
489    return;
490
491  // Generate an error.  Only generate a sink error node
492  // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node.
493  //
494  // FIXME: We can actually create an abstract "CFNumber" object that has
495  //  the bits initialized to the provided values.
496  //
497  ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode()
498                                            : C.generateNonFatalErrorNode();
499  if (N) {
500    SmallString<128> sbuf;
501    llvm::raw_svector_ostream os(sbuf);
502
503    os << (SourceSize == 8 ? "An " : "A ")
504       << SourceSize << " bit integer is used to initialize a CFNumber "
505                        "object that represents "
506       << (TargetSize == 8 ? "an " : "a ")
507       << TargetSize << " bit integer. ";
508
509    if (SourceSize < TargetSize)
510      os << (TargetSize - SourceSize)
511      << " bits of the CFNumber value will be garbage." ;
512    else
513      os << (SourceSize - TargetSize)
514      << " bits of the input integer will be lost.";
515
516    if (!BT)
517      BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
518
519    auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
520    report->addRange(CE->getArg(2)->getSourceRange());
521    C.emitReport(std::move(report));
522  }
523}
524
525//===----------------------------------------------------------------------===//
526// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
527//===----------------------------------------------------------------------===//
528
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.generateErrorNode(stateTrue);
593    if (!N)
594      return;
595
596    const char *description;
597    if (FuncII == Retain)
598      description = "Null pointer argument in call to CFRetain";
599    else if (FuncII == Release)
600      description = "Null pointer argument in call to CFRelease";
601    else if (FuncII == MakeCollectable)
602      description = "Null pointer argument in call to CFMakeCollectable";
603    else if (FuncII == Autorelease)
604      description = "Null pointer argument in call to CFAutorelease";
605    else
606      llvm_unreachable("impossible case");
607
608    auto report = llvm::make_unique<BugReport>(*BT, description, N);
609    report->addRange(Arg->getSourceRange());
610    bugreporter::trackNullOrUndefValue(N, Arg, *report);
611    C.emitReport(std::move(report));
612    return;
613  }
614
615  // From here on, we know the argument is non-null.
616  C.addTransition(stateFalse);
617}
618
619//===----------------------------------------------------------------------===//
620// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
621//===----------------------------------------------------------------------===//
622
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.generateNonFatalErrorNode()) {
660    SmallString<200> buf;
661    llvm::raw_svector_ostream os(buf);
662
663    os << "The '";
664    S.print(os);
665    os << "' message should be sent to instances "
666          "of class '" << Class->getName()
667       << "' and not the class directly";
668
669    auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
670    report->addRange(msg.getSourceRange());
671    C.emitReport(std::move(report));
672  }
673}
674
675//===----------------------------------------------------------------------===//
676// Check for passing non-Objective-C types to variadic methods that expect
677// only Objective-C types.
678//===----------------------------------------------------------------------===//
679
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.generateNonFatalErrorNode();
804
805    if (!errorNode.getValue())
806      continue;
807
808    SmallString<128> sbuf;
809    llvm::raw_svector_ostream os(sbuf);
810
811    StringRef TypeName = GetReceiverInterfaceName(msg);
812    if (!TypeName.empty())
813      os << "Argument to '" << TypeName << "' method '";
814    else
815      os << "Argument to method '";
816
817    msg.getSelector().print(os);
818    os << "' should be an Objective-C pointer type, not '";
819    ArgTy.print(os, C.getLangOpts());
820    os << "'";
821
822    auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
823    R->addRange(msg.getArgSourceRange(I));
824    C.emitReport(std::move(R));
825  }
826}
827
828//===----------------------------------------------------------------------===//
829// Improves the modeling of loops over Cocoa collections.
830//===----------------------------------------------------------------------===//
831
832// The map from container symbol to the container count symbol.
833// We currently will remember the last countainer count symbol encountered.
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    return BE->getSrc()->getLoopTarget() == FCS;
996  }
997
998  // Keep looking for a block edge.
999  for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
1000                                         E = N->pred_end(); I != E; ++I) {
1001    if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
1002      return true;
1003  }
1004
1005  return false;
1006}
1007
1008void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1009                                    CheckerContext &C) const {
1010  ProgramStateRef State = C.getState();
1011
1012  // Check if this is the branch for the end of the loop.
1013  SVal CollectionSentinel = C.getSVal(FCS);
1014  if (CollectionSentinel.isZeroConstant()) {
1015    if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
1016      State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1017
1018  // Otherwise, this is a branch that goes through the loop body.
1019  } else {
1020    State = checkCollectionNonNil(C, State, FCS);
1021    State = checkElementNonNil(C, State, FCS);
1022    State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1023  }
1024
1025  if (!State)
1026    C.generateSink(C.getState(), C.getPredecessor());
1027  else if (State != C.getState())
1028    C.addTransition(State);
1029}
1030
1031bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1032                                              CheckerContext &C) const {
1033  Selector S = M.getSelector();
1034  // Initialize the identifiers on first use.
1035  if (!CountSelectorII)
1036    CountSelectorII = &C.getASTContext().Idents.get("count");
1037
1038  // If the method returns collection count, record the value.
1039  return S.isUnarySelector() &&
1040         (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1041}
1042
1043void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1044                                           CheckerContext &C) const {
1045  if (!M.isInstanceMessage())
1046    return;
1047
1048  const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1049  if (!ClassID)
1050    return;
1051
1052  FoundationClass Class = findKnownClass(ClassID);
1053  if (Class != FC_NSDictionary &&
1054      Class != FC_NSArray &&
1055      Class != FC_NSSet &&
1056      Class != FC_NSOrderedSet)
1057    return;
1058
1059  SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1060  if (!ContainerS)
1061    return;
1062
1063  // If we are processing a call to "count", get the symbolic value returned by
1064  // a call to "count" and add it to the map.
1065  if (!isCollectionCountMethod(M, C))
1066    return;
1067
1068  const Expr *MsgExpr = M.getOriginExpr();
1069  SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1070  if (CountS) {
1071    ProgramStateRef State = C.getState();
1072
1073    C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1074    State = State->set<ContainerCountMap>(ContainerS, CountS);
1075
1076    if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1077      State = State->remove<ContainerNonEmptyMap>(ContainerS);
1078      State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1079    }
1080
1081    C.addTransition(State);
1082  }
1083  return;
1084}
1085
1086static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1087  const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1088  if (!Message)
1089    return nullptr;
1090
1091  const ObjCMethodDecl *MD = Message->getDecl();
1092  if (!MD)
1093    return nullptr;
1094
1095  const ObjCInterfaceDecl *StaticClass;
1096  if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1097    // We can't find out where the method was declared without doing more work.
1098    // Instead, see if the receiver is statically typed as a known immutable
1099    // collection.
1100    StaticClass = Message->getOriginExpr()->getReceiverInterface();
1101  } else {
1102    StaticClass = MD->getClassInterface();
1103  }
1104
1105  if (!StaticClass)
1106    return nullptr;
1107
1108  switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1109  case FC_None:
1110    return nullptr;
1111  case FC_NSArray:
1112  case FC_NSDictionary:
1113  case FC_NSEnumerator:
1114  case FC_NSNull:
1115  case FC_NSOrderedSet:
1116  case FC_NSSet:
1117  case FC_NSString:
1118    break;
1119  }
1120
1121  return Message->getReceiverSVal().getAsSymbol();
1122}
1123
1124ProgramStateRef
1125ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1126                                    const InvalidatedSymbols &Escaped,
1127                                    const CallEvent *Call,
1128                                    PointerEscapeKind Kind) const {
1129  SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1130
1131  // Remove the invalidated symbols form the collection count map.
1132  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1133       E = Escaped.end();
1134       I != E; ++I) {
1135    SymbolRef Sym = *I;
1136
1137    // Don't invalidate this symbol's count if we know the method being called
1138    // is declared on an immutable class. This isn't completely correct if the
1139    // receiver is also passed as an argument, but in most uses of NSArray,
1140    // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1141    if (Sym == ImmutableReceiver)
1142      continue;
1143
1144    // The symbol escaped. Pessimistically, assume that the count could have
1145    // changed.
1146    State = State->remove<ContainerCountMap>(Sym);
1147    State = State->remove<ContainerNonEmptyMap>(Sym);
1148  }
1149  return State;
1150}
1151
1152void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1153                                       CheckerContext &C) const {
1154  ProgramStateRef State = C.getState();
1155
1156  // Remove the dead symbols from the collection count map.
1157  ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1158  for (ContainerCountMapTy::iterator I = Tracked.begin(),
1159                                     E = Tracked.end(); I != E; ++I) {
1160    SymbolRef Sym = I->first;
1161    if (SymReaper.isDead(Sym)) {
1162      State = State->remove<ContainerCountMap>(Sym);
1163      State = State->remove<ContainerNonEmptyMap>(Sym);
1164    }
1165  }
1166
1167  C.addTransition(State);
1168}
1169
1170namespace {
1171/// \class ObjCNonNilReturnValueChecker
1172/// \brief The checker restricts the return values of APIs known to
1173/// never (or almost never) return 'nil'.
1174class ObjCNonNilReturnValueChecker
1175  : public Checker<check::PostObjCMessage,
1176                   check::PostStmt<ObjCArrayLiteral>,
1177                   check::PostStmt<ObjCDictionaryLiteral>,
1178                   check::PostStmt<ObjCBoxedExpr> > {
1179    mutable bool Initialized;
1180    mutable Selector ObjectAtIndex;
1181    mutable Selector ObjectAtIndexedSubscript;
1182    mutable Selector NullSelector;
1183
1184public:
1185  ObjCNonNilReturnValueChecker() : Initialized(false) {}
1186
1187  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1188                                      ProgramStateRef State,
1189                                      CheckerContext &C) const;
1190  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1191    C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1192  }
1193
1194  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1195    assumeExprIsNonNull(E, C);
1196  }
1197  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1198    assumeExprIsNonNull(E, C);
1199  }
1200  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1201    assumeExprIsNonNull(E, C);
1202  }
1203
1204  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1205};
1206}
1207
1208ProgramStateRef
1209ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1210                                                  ProgramStateRef State,
1211                                                  CheckerContext &C) const {
1212  SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
1213  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1214    return State->assume(*DV, true);
1215  return State;
1216}
1217
1218void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1219                                                        CheckerContext &C)
1220                                                        const {
1221  ProgramStateRef State = C.getState();
1222
1223  if (!Initialized) {
1224    ASTContext &Ctx = C.getASTContext();
1225    ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1226    ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1227    NullSelector = GetNullarySelector("null", Ctx);
1228  }
1229
1230  // Check the receiver type.
1231  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1232
1233    // Assume that object returned from '[self init]' or '[super init]' is not
1234    // 'nil' if we are processing an inlined function/method.
1235    //
1236    // A defensive callee will (and should) check if the object returned by
1237    // '[super init]' is 'nil' before doing it's own initialization. However,
1238    // since 'nil' is rarely returned in practice, we should not warn when the
1239    // caller to the defensive constructor uses the object in contexts where
1240    // 'nil' is not accepted.
1241    if (!C.inTopFrame() && M.getDecl() &&
1242        M.getDecl()->getMethodFamily() == OMF_init &&
1243        M.isReceiverSelfOrSuper()) {
1244      State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1245    }
1246
1247    FoundationClass Cl = findKnownClass(Interface);
1248
1249    // Objects returned from
1250    // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1251    // are never 'nil'.
1252    if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1253      Selector Sel = M.getSelector();
1254      if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1255        // Go ahead and assume the value is non-nil.
1256        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1257      }
1258    }
1259
1260    // Objects returned from [NSNull null] are not nil.
1261    if (Cl == FC_NSNull) {
1262      if (M.getSelector() == NullSelector) {
1263        // Go ahead and assume the value is non-nil.
1264        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1265      }
1266    }
1267  }
1268  C.addTransition(State);
1269}
1270
1271//===----------------------------------------------------------------------===//
1272// Check registration.
1273//===----------------------------------------------------------------------===//
1274
1275void ento::registerNilArgChecker(CheckerManager &mgr) {
1276  mgr.registerChecker<NilArgChecker>();
1277}
1278
1279void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
1280  mgr.registerChecker<CFNumberCreateChecker>();
1281}
1282
1283void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1284  mgr.registerChecker<CFRetainReleaseChecker>();
1285}
1286
1287void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1288  mgr.registerChecker<ClassReleaseChecker>();
1289}
1290
1291void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1292  mgr.registerChecker<VariadicMethodTypeChecker>();
1293}
1294
1295void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1296  mgr.registerChecker<ObjCLoopChecker>();
1297}
1298
1299void
1300ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1301  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1302}
1303