BasicObjCFoundationChecks.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
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 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;
533public:
534  CFRetainReleaseChecker()
535      : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr) {}
536  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
537};
538} // end anonymous namespace
539
540
541void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
542                                          CheckerContext &C) const {
543  // If the CallExpr doesn't have exactly 1 argument just give up checking.
544  if (CE->getNumArgs() != 1)
545    return;
546
547  ProgramStateRef state = C.getState();
548  const FunctionDecl *FD = C.getCalleeDecl(CE);
549  if (!FD)
550    return;
551
552  if (!BT) {
553    ASTContext &Ctx = C.getASTContext();
554    Retain = &Ctx.Idents.get("CFRetain");
555    Release = &Ctx.Idents.get("CFRelease");
556    MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
557    BT.reset(new APIMisuse(
558        this, "null passed to CFRetain/CFRelease/CFMakeCollectable"));
559  }
560
561  // Check if we called CFRetain/CFRelease/CFMakeCollectable.
562  const IdentifierInfo *FuncII = FD->getIdentifier();
563  if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
564    return;
565
566  // FIXME: The rest of this just checks that the argument is non-null.
567  // It should probably be refactored and combined with NonNullParamChecker.
568
569  // Get the argument's value.
570  const Expr *Arg = CE->getArg(0);
571  SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
572  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
573  if (!DefArgVal)
574    return;
575
576  // Get a NULL value.
577  SValBuilder &svalBuilder = C.getSValBuilder();
578  DefinedSVal zero =
579      svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
580
581  // Make an expression asserting that they're equal.
582  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
583
584  // Are they equal?
585  ProgramStateRef stateTrue, stateFalse;
586  std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
587
588  if (stateTrue && !stateFalse) {
589    ExplodedNode *N = C.generateSink(stateTrue);
590    if (!N)
591      return;
592
593    const char *description;
594    if (FuncII == Retain)
595      description = "Null pointer argument in call to CFRetain";
596    else if (FuncII == Release)
597      description = "Null pointer argument in call to CFRelease";
598    else if (FuncII == MakeCollectable)
599      description = "Null pointer argument in call to CFMakeCollectable";
600    else
601      llvm_unreachable("impossible case");
602
603    BugReport *report = new BugReport(*BT, description, N);
604    report->addRange(Arg->getSourceRange());
605    bugreporter::trackNullOrUndefValue(N, Arg, *report);
606    C.emitReport(report);
607    return;
608  }
609
610  // From here on, we know the argument is non-null.
611  C.addTransition(stateFalse);
612}
613
614//===----------------------------------------------------------------------===//
615// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
616//===----------------------------------------------------------------------===//
617
618namespace {
619class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
620  mutable Selector releaseS;
621  mutable Selector retainS;
622  mutable Selector autoreleaseS;
623  mutable Selector drainS;
624  mutable std::unique_ptr<BugType> BT;
625
626public:
627  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
628};
629}
630
631void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
632                                              CheckerContext &C) const {
633
634  if (!BT) {
635    BT.reset(new APIMisuse(
636        this, "message incorrectly sent to class instead of class instance"));
637
638    ASTContext &Ctx = C.getASTContext();
639    releaseS = GetNullarySelector("release", Ctx);
640    retainS = GetNullarySelector("retain", Ctx);
641    autoreleaseS = GetNullarySelector("autorelease", Ctx);
642    drainS = GetNullarySelector("drain", Ctx);
643  }
644
645  if (msg.isInstanceMessage())
646    return;
647  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
648  assert(Class);
649
650  Selector S = msg.getSelector();
651  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
652    return;
653
654  if (ExplodedNode *N = C.addTransition()) {
655    SmallString<200> buf;
656    llvm::raw_svector_ostream os(buf);
657
658    os << "The '";
659    S.print(os);
660    os << "' message should be sent to instances "
661          "of class '" << Class->getName()
662       << "' and not the class directly";
663
664    BugReport *report = new BugReport(*BT, os.str(), N);
665    report->addRange(msg.getSourceRange());
666    C.emitReport(report);
667  }
668}
669
670//===----------------------------------------------------------------------===//
671// Check for passing non-Objective-C types to variadic methods that expect
672// only Objective-C types.
673//===----------------------------------------------------------------------===//
674
675namespace {
676class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
677  mutable Selector arrayWithObjectsS;
678  mutable Selector dictionaryWithObjectsAndKeysS;
679  mutable Selector setWithObjectsS;
680  mutable Selector orderedSetWithObjectsS;
681  mutable Selector initWithObjectsS;
682  mutable Selector initWithObjectsAndKeysS;
683  mutable std::unique_ptr<BugType> BT;
684
685  bool isVariadicMessage(const ObjCMethodCall &msg) const;
686
687public:
688  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
689};
690}
691
692/// isVariadicMessage - Returns whether the given message is a variadic message,
693/// where all arguments must be Objective-C types.
694bool
695VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
696  const ObjCMethodDecl *MD = msg.getDecl();
697
698  if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
699    return false;
700
701  Selector S = msg.getSelector();
702
703  if (msg.isInstanceMessage()) {
704    // FIXME: Ideally we'd look at the receiver interface here, but that's not
705    // useful for init, because alloc returns 'id'. In theory, this could lead
706    // to false positives, for example if there existed a class that had an
707    // initWithObjects: implementation that does accept non-Objective-C pointer
708    // types, but the chance of that happening is pretty small compared to the
709    // gains that this analysis gives.
710    const ObjCInterfaceDecl *Class = MD->getClassInterface();
711
712    switch (findKnownClass(Class)) {
713    case FC_NSArray:
714    case FC_NSOrderedSet:
715    case FC_NSSet:
716      return S == initWithObjectsS;
717    case FC_NSDictionary:
718      return S == initWithObjectsAndKeysS;
719    default:
720      return false;
721    }
722  } else {
723    const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
724
725    switch (findKnownClass(Class)) {
726      case FC_NSArray:
727        return S == arrayWithObjectsS;
728      case FC_NSOrderedSet:
729        return S == orderedSetWithObjectsS;
730      case FC_NSSet:
731        return S == setWithObjectsS;
732      case FC_NSDictionary:
733        return S == dictionaryWithObjectsAndKeysS;
734      default:
735        return false;
736    }
737  }
738}
739
740void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
741                                                    CheckerContext &C) const {
742  if (!BT) {
743    BT.reset(new APIMisuse(this,
744                           "Arguments passed to variadic method aren't all "
745                           "Objective-C pointer types"));
746
747    ASTContext &Ctx = C.getASTContext();
748    arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
749    dictionaryWithObjectsAndKeysS =
750      GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
751    setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
752    orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
753
754    initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
755    initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
756  }
757
758  if (!isVariadicMessage(msg))
759      return;
760
761  // We are not interested in the selector arguments since they have
762  // well-defined types, so the compiler will issue a warning for them.
763  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
764
765  // We're not interested in the last argument since it has to be nil or the
766  // compiler would have issued a warning for it elsewhere.
767  unsigned variadicArgsEnd = msg.getNumArgs() - 1;
768
769  if (variadicArgsEnd <= variadicArgsBegin)
770    return;
771
772  // Verify that all arguments have Objective-C types.
773  Optional<ExplodedNode*> errorNode;
774
775  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
776    QualType ArgTy = msg.getArgExpr(I)->getType();
777    if (ArgTy->isObjCObjectPointerType())
778      continue;
779
780    // Block pointers are treaded as Objective-C pointers.
781    if (ArgTy->isBlockPointerType())
782      continue;
783
784    // Ignore pointer constants.
785    if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
786      continue;
787
788    // Ignore pointer types annotated with 'NSObject' attribute.
789    if (C.getASTContext().isObjCNSObjectType(ArgTy))
790      continue;
791
792    // Ignore CF references, which can be toll-free bridged.
793    if (coreFoundation::isCFObjectRef(ArgTy))
794      continue;
795
796    // Generate only one error node to use for all bug reports.
797    if (!errorNode.hasValue())
798      errorNode = C.addTransition();
799
800    if (!errorNode.getValue())
801      continue;
802
803    SmallString<128> sbuf;
804    llvm::raw_svector_ostream os(sbuf);
805
806    StringRef TypeName = GetReceiverInterfaceName(msg);
807    if (!TypeName.empty())
808      os << "Argument to '" << TypeName << "' method '";
809    else
810      os << "Argument to method '";
811
812    msg.getSelector().print(os);
813    os << "' should be an Objective-C pointer type, not '";
814    ArgTy.print(os, C.getLangOpts());
815    os << "'";
816
817    BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
818    R->addRange(msg.getArgSourceRange(I));
819    C.emitReport(R);
820  }
821}
822
823//===----------------------------------------------------------------------===//
824// Improves the modeling of loops over Cocoa collections.
825//===----------------------------------------------------------------------===//
826
827// The map from container symbol to the container count symbol.
828// We currently will remember the last countainer count symbol encountered.
829REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
830REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
831
832namespace {
833class ObjCLoopChecker
834  : public Checker<check::PostStmt<ObjCForCollectionStmt>,
835                   check::PostObjCMessage,
836                   check::DeadSymbols,
837                   check::PointerEscape > {
838  mutable IdentifierInfo *CountSelectorII;
839
840  bool isCollectionCountMethod(const ObjCMethodCall &M,
841                               CheckerContext &C) const;
842
843public:
844  ObjCLoopChecker() : CountSelectorII(nullptr) {}
845  void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
846  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
847  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
848  ProgramStateRef checkPointerEscape(ProgramStateRef State,
849                                     const InvalidatedSymbols &Escaped,
850                                     const CallEvent *Call,
851                                     PointerEscapeKind Kind) const;
852};
853}
854
855static bool isKnownNonNilCollectionType(QualType T) {
856  const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
857  if (!PT)
858    return false;
859
860  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
861  if (!ID)
862    return false;
863
864  switch (findKnownClass(ID)) {
865  case FC_NSArray:
866  case FC_NSDictionary:
867  case FC_NSEnumerator:
868  case FC_NSOrderedSet:
869  case FC_NSSet:
870    return true;
871  default:
872    return false;
873  }
874}
875
876/// Assumes that the collection is non-nil.
877///
878/// If the collection is known to be nil, returns NULL to indicate an infeasible
879/// path.
880static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
881                                             ProgramStateRef State,
882                                             const ObjCForCollectionStmt *FCS) {
883  if (!State)
884    return nullptr;
885
886  SVal CollectionVal = C.getSVal(FCS->getCollection());
887  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
888  if (!KnownCollection)
889    return State;
890
891  ProgramStateRef StNonNil, StNil;
892  std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
893  if (StNil && !StNonNil) {
894    // The collection is nil. This path is infeasible.
895    return nullptr;
896  }
897
898  return StNonNil;
899}
900
901/// Assumes that the collection elements are non-nil.
902///
903/// This only applies if the collection is one of those known not to contain
904/// nil values.
905static ProgramStateRef checkElementNonNil(CheckerContext &C,
906                                          ProgramStateRef State,
907                                          const ObjCForCollectionStmt *FCS) {
908  if (!State)
909    return nullptr;
910
911  // See if the collection is one where we /know/ the elements are non-nil.
912  if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
913    return State;
914
915  const LocationContext *LCtx = C.getLocationContext();
916  const Stmt *Element = FCS->getElement();
917
918  // FIXME: Copied from ExprEngineObjC.
919  Optional<Loc> ElementLoc;
920  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
921    const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
922    assert(ElemDecl->getInit() == nullptr);
923    ElementLoc = State->getLValue(ElemDecl, LCtx);
924  } else {
925    ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
926  }
927
928  if (!ElementLoc)
929    return State;
930
931  // Go ahead and assume the value is non-nil.
932  SVal Val = State->getSVal(*ElementLoc);
933  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
934}
935
936/// Returns NULL state if the collection is known to contain elements
937/// (or is known not to contain elements if the Assumption parameter is false.)
938static ProgramStateRef
939assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
940                         SymbolRef CollectionS, bool Assumption) {
941  if (!State || !CollectionS)
942    return State;
943
944  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
945  if (!CountS) {
946    const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
947    if (!KnownNonEmpty)
948      return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
949    return (Assumption == *KnownNonEmpty) ? State : nullptr;
950  }
951
952  SValBuilder &SvalBuilder = C.getSValBuilder();
953  SVal CountGreaterThanZeroVal =
954    SvalBuilder.evalBinOp(State, BO_GT,
955                          nonloc::SymbolVal(*CountS),
956                          SvalBuilder.makeIntVal(0, (*CountS)->getType()),
957                          SvalBuilder.getConditionType());
958  Optional<DefinedSVal> CountGreaterThanZero =
959    CountGreaterThanZeroVal.getAs<DefinedSVal>();
960  if (!CountGreaterThanZero) {
961    // The SValBuilder cannot construct a valid SVal for this condition.
962    // This means we cannot properly reason about it.
963    return State;
964  }
965
966  return State->assume(*CountGreaterThanZero, Assumption);
967}
968
969static ProgramStateRef
970assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
971                         const ObjCForCollectionStmt *FCS,
972                         bool Assumption) {
973  if (!State)
974    return nullptr;
975
976  SymbolRef CollectionS =
977    State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
978  return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
979}
980
981
982/// If the fist block edge is a back edge, we are reentering the loop.
983static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
984                                             const ObjCForCollectionStmt *FCS) {
985  if (!N)
986    return false;
987
988  ProgramPoint P = N->getLocation();
989  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
990    if (BE->getSrc()->getLoopTarget() == FCS)
991      return true;
992    return false;
993  }
994
995  // Keep looking for a block edge.
996  for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
997                                         E = N->pred_end(); I != E; ++I) {
998    if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
999      return true;
1000  }
1001
1002  return false;
1003}
1004
1005void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
1006                                    CheckerContext &C) const {
1007  ProgramStateRef State = C.getState();
1008
1009  // Check if this is the branch for the end of the loop.
1010  SVal CollectionSentinel = C.getSVal(FCS);
1011  if (CollectionSentinel.isZeroConstant()) {
1012    if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
1013      State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
1014
1015  // Otherwise, this is a branch that goes through the loop body.
1016  } else {
1017    State = checkCollectionNonNil(C, State, FCS);
1018    State = checkElementNonNil(C, State, FCS);
1019    State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
1020  }
1021
1022  if (!State)
1023    C.generateSink();
1024  else if (State != C.getState())
1025    C.addTransition(State);
1026}
1027
1028bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1029                                              CheckerContext &C) const {
1030  Selector S = M.getSelector();
1031  // Initialize the identifiers on first use.
1032  if (!CountSelectorII)
1033    CountSelectorII = &C.getASTContext().Idents.get("count");
1034
1035  // If the method returns collection count, record the value.
1036  if (S.isUnarySelector() &&
1037      (S.getIdentifierInfoForSlot(0) == CountSelectorII))
1038    return true;
1039
1040  return false;
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