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