xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (revision 721567af3ec2a0f453f3cd9380a36a9ded7158f5)
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 "clang/Analysis/DomainSpecific/CocoaConventions.h"
18 #include "clang/StaticAnalyzer/Core/Checker.h"
19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
24 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
25 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
27 #include "clang/AST/DeclObjC.h"
28 #include "clang/AST/Expr.h"
29 #include "clang/AST/ExprObjC.h"
30 #include "clang/AST/StmtObjC.h"
31 #include "clang/AST/ASTContext.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/StringMap.h"
34 
35 using namespace clang;
36 using namespace ento;
37 
38 namespace {
39 class APIMisuse : public BugType {
40 public:
41   APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
42 };
43 } // end anonymous namespace
44 
45 //===----------------------------------------------------------------------===//
46 // Utility functions.
47 //===----------------------------------------------------------------------===//
48 
49 static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
50   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
51     return ID->getIdentifier()->getName();
52   return StringRef();
53 }
54 
55 enum FoundationClass {
56   FC_None,
57   FC_NSArray,
58   FC_NSDictionary,
59   FC_NSEnumerator,
60   FC_NSOrderedSet,
61   FC_NSSet,
62   FC_NSString
63 };
64 
65 static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
66   static llvm::StringMap<FoundationClass> Classes;
67   if (Classes.empty()) {
68     Classes["NSArray"] = FC_NSArray;
69     Classes["NSDictionary"] = FC_NSDictionary;
70     Classes["NSEnumerator"] = FC_NSEnumerator;
71     Classes["NSOrderedSet"] = FC_NSOrderedSet;
72     Classes["NSSet"] = FC_NSSet;
73     Classes["NSString"] = FC_NSString;
74   }
75 
76   // FIXME: Should we cache this at all?
77   FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
78   if (result == FC_None)
79     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
80       return findKnownClass(Super);
81 
82   return result;
83 }
84 
85 static inline bool isNil(SVal X) {
86   return isa<loc::ConcreteInt>(X);
87 }
88 
89 //===----------------------------------------------------------------------===//
90 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
91 //===----------------------------------------------------------------------===//
92 
93 namespace {
94   class NilArgChecker : public Checker<check::PreObjCMessage> {
95     mutable OwningPtr<APIMisuse> BT;
96 
97     void WarnNilArg(CheckerContext &C,
98                     const ObjCMethodCall &msg, unsigned Arg) const;
99 
100   public:
101     void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
102   };
103 }
104 
105 void NilArgChecker::WarnNilArg(CheckerContext &C,
106                                const ObjCMethodCall &msg,
107                                unsigned int Arg) const
108 {
109   if (!BT)
110     BT.reset(new APIMisuse("nil argument"));
111 
112   if (ExplodedNode *N = C.generateSink()) {
113     SmallString<128> sbuf;
114     llvm::raw_svector_ostream os(sbuf);
115     os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
116        << msg.getSelector().getAsString() << "' cannot be nil";
117 
118     BugReport *R = new BugReport(*BT, os.str(), N);
119     R->addRange(msg.getArgSourceRange(Arg));
120     C.emitReport(R);
121   }
122 }
123 
124 void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
125                                         CheckerContext &C) const {
126   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
127   if (!ID)
128     return;
129 
130   if (findKnownClass(ID) == FC_NSString) {
131     Selector S = msg.getSelector();
132 
133     if (S.isUnarySelector())
134       return;
135 
136     // FIXME: This is going to be really slow doing these checks with
137     //  lexical comparisons.
138 
139     std::string NameStr = S.getAsString();
140     StringRef Name(NameStr);
141     assert(!Name.empty());
142 
143     // FIXME: Checking for initWithFormat: will not work in most cases
144     //  yet because [NSString alloc] returns id, not NSString*.  We will
145     //  need support for tracking expected-type information in the analyzer
146     //  to find these errors.
147     if (Name == "caseInsensitiveCompare:" ||
148         Name == "compare:" ||
149         Name == "compare:options:" ||
150         Name == "compare:options:range:" ||
151         Name == "compare:options:range:locale:" ||
152         Name == "componentsSeparatedByCharactersInSet:" ||
153         Name == "initWithFormat:") {
154       if (isNil(msg.getArgSVal(0)))
155         WarnNilArg(C, msg, 0);
156     }
157   }
158 }
159 
160 //===----------------------------------------------------------------------===//
161 // Error reporting.
162 //===----------------------------------------------------------------------===//
163 
164 namespace {
165 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
166   mutable OwningPtr<APIMisuse> BT;
167   mutable IdentifierInfo* II;
168 public:
169   CFNumberCreateChecker() : II(0) {}
170 
171   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
172 
173 private:
174   void EmitError(const TypedRegion* R, const Expr *Ex,
175                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
176 };
177 } // end anonymous namespace
178 
179 enum CFNumberType {
180   kCFNumberSInt8Type = 1,
181   kCFNumberSInt16Type = 2,
182   kCFNumberSInt32Type = 3,
183   kCFNumberSInt64Type = 4,
184   kCFNumberFloat32Type = 5,
185   kCFNumberFloat64Type = 6,
186   kCFNumberCharType = 7,
187   kCFNumberShortType = 8,
188   kCFNumberIntType = 9,
189   kCFNumberLongType = 10,
190   kCFNumberLongLongType = 11,
191   kCFNumberFloatType = 12,
192   kCFNumberDoubleType = 13,
193   kCFNumberCFIndexType = 14,
194   kCFNumberNSIntegerType = 15,
195   kCFNumberCGFloatType = 16
196 };
197 
198 namespace {
199   template<typename T>
200   class Optional {
201     bool IsKnown;
202     T Val;
203   public:
204     Optional() : IsKnown(false), Val(0) {}
205     Optional(const T& val) : IsKnown(true), Val(val) {}
206 
207     bool isKnown() const { return IsKnown; }
208 
209     const T& getValue() const {
210       assert (isKnown());
211       return Val;
212     }
213 
214     operator const T&() const {
215       return getValue();
216     }
217   };
218 }
219 
220 static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
221   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
222 
223   if (i < kCFNumberCharType)
224     return FixedSize[i-1];
225 
226   QualType T;
227 
228   switch (i) {
229     case kCFNumberCharType:     T = Ctx.CharTy;     break;
230     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
231     case kCFNumberIntType:      T = Ctx.IntTy;      break;
232     case kCFNumberLongType:     T = Ctx.LongTy;     break;
233     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
234     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
235     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
236     case kCFNumberCFIndexType:
237     case kCFNumberNSIntegerType:
238     case kCFNumberCGFloatType:
239       // FIXME: We need a way to map from names to Type*.
240     default:
241       return Optional<uint64_t>();
242   }
243 
244   return Ctx.getTypeSize(T);
245 }
246 
247 #if 0
248 static const char* GetCFNumberTypeStr(uint64_t i) {
249   static const char* Names[] = {
250     "kCFNumberSInt8Type",
251     "kCFNumberSInt16Type",
252     "kCFNumberSInt32Type",
253     "kCFNumberSInt64Type",
254     "kCFNumberFloat32Type",
255     "kCFNumberFloat64Type",
256     "kCFNumberCharType",
257     "kCFNumberShortType",
258     "kCFNumberIntType",
259     "kCFNumberLongType",
260     "kCFNumberLongLongType",
261     "kCFNumberFloatType",
262     "kCFNumberDoubleType",
263     "kCFNumberCFIndexType",
264     "kCFNumberNSIntegerType",
265     "kCFNumberCGFloatType"
266   };
267 
268   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
269 }
270 #endif
271 
272 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
273                                          CheckerContext &C) const {
274   ProgramStateRef state = C.getState();
275   const FunctionDecl *FD = C.getCalleeDecl(CE);
276   if (!FD)
277     return;
278 
279   ASTContext &Ctx = C.getASTContext();
280   if (!II)
281     II = &Ctx.Idents.get("CFNumberCreate");
282 
283   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
284     return;
285 
286   // Get the value of the "theType" argument.
287   const LocationContext *LCtx = C.getLocationContext();
288   SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
289 
290   // FIXME: We really should allow ranges of valid theType values, and
291   //   bifurcate the state appropriately.
292   nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
293   if (!V)
294     return;
295 
296   uint64_t NumberKind = V->getValue().getLimitedValue();
297   Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
298 
299   // FIXME: In some cases we can emit an error.
300   if (!TargetSize.isKnown())
301     return;
302 
303   // Look at the value of the integer being passed by reference.  Essentially
304   // we want to catch cases where the value passed in is not equal to the
305   // size of the type being created.
306   SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
307 
308   // FIXME: Eventually we should handle arbitrary locations.  We can do this
309   //  by having an enhanced memory model that does low-level typing.
310   loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
311   if (!LV)
312     return;
313 
314   const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
315   if (!R)
316     return;
317 
318   QualType T = Ctx.getCanonicalType(R->getValueType());
319 
320   // FIXME: If the pointee isn't an integer type, should we flag a warning?
321   //  People can do weird stuff with pointers.
322 
323   if (!T->isIntegerType())
324     return;
325 
326   uint64_t SourceSize = Ctx.getTypeSize(T);
327 
328   // CHECK: is SourceSize == TargetSize
329   if (SourceSize == TargetSize)
330     return;
331 
332   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
333   // otherwise generate a regular node.
334   //
335   // FIXME: We can actually create an abstract "CFNumber" object that has
336   //  the bits initialized to the provided values.
337   //
338   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
339                                                 : C.addTransition()) {
340     SmallString<128> sbuf;
341     llvm::raw_svector_ostream os(sbuf);
342 
343     os << (SourceSize == 8 ? "An " : "A ")
344        << SourceSize << " bit integer is used to initialize a CFNumber "
345                         "object that represents "
346        << (TargetSize == 8 ? "an " : "a ")
347        << TargetSize << " bit integer. ";
348 
349     if (SourceSize < TargetSize)
350       os << (TargetSize - SourceSize)
351       << " bits of the CFNumber value will be garbage." ;
352     else
353       os << (SourceSize - TargetSize)
354       << " bits of the input integer will be lost.";
355 
356     if (!BT)
357       BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
358 
359     BugReport *report = new BugReport(*BT, os.str(), N);
360     report->addRange(CE->getArg(2)->getSourceRange());
361     C.emitReport(report);
362   }
363 }
364 
365 //===----------------------------------------------------------------------===//
366 // CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
367 //===----------------------------------------------------------------------===//
368 
369 namespace {
370 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
371   mutable OwningPtr<APIMisuse> BT;
372   mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
373 public:
374   CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
375   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
376 };
377 } // end anonymous namespace
378 
379 
380 void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
381                                           CheckerContext &C) const {
382   // If the CallExpr doesn't have exactly 1 argument just give up checking.
383   if (CE->getNumArgs() != 1)
384     return;
385 
386   ProgramStateRef state = C.getState();
387   const FunctionDecl *FD = C.getCalleeDecl(CE);
388   if (!FD)
389     return;
390 
391   if (!BT) {
392     ASTContext &Ctx = C.getASTContext();
393     Retain = &Ctx.Idents.get("CFRetain");
394     Release = &Ctx.Idents.get("CFRelease");
395     MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
396     BT.reset(
397       new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
398   }
399 
400   // Check if we called CFRetain/CFRelease/CFMakeCollectable.
401   const IdentifierInfo *FuncII = FD->getIdentifier();
402   if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
403     return;
404 
405   // FIXME: The rest of this just checks that the argument is non-null.
406   // It should probably be refactored and combined with AttrNonNullChecker.
407 
408   // Get the argument's value.
409   const Expr *Arg = CE->getArg(0);
410   SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
411   DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
412   if (!DefArgVal)
413     return;
414 
415   // Get a NULL value.
416   SValBuilder &svalBuilder = C.getSValBuilder();
417   DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
418 
419   // Make an expression asserting that they're equal.
420   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
421 
422   // Are they equal?
423   ProgramStateRef stateTrue, stateFalse;
424   llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
425 
426   if (stateTrue && !stateFalse) {
427     ExplodedNode *N = C.generateSink(stateTrue);
428     if (!N)
429       return;
430 
431     const char *description;
432     if (FuncII == Retain)
433       description = "Null pointer argument in call to CFRetain";
434     else if (FuncII == Release)
435       description = "Null pointer argument in call to CFRelease";
436     else if (FuncII == MakeCollectable)
437       description = "Null pointer argument in call to CFMakeCollectable";
438     else
439       llvm_unreachable("impossible case");
440 
441     BugReport *report = new BugReport(*BT, description, N);
442     report->addRange(Arg->getSourceRange());
443     bugreporter::trackNullOrUndefValue(N, Arg, *report);
444     C.emitReport(report);
445     return;
446   }
447 
448   // From here on, we know the argument is non-null.
449   C.addTransition(stateFalse);
450 }
451 
452 //===----------------------------------------------------------------------===//
453 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
454 //===----------------------------------------------------------------------===//
455 
456 namespace {
457 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
458   mutable Selector releaseS;
459   mutable Selector retainS;
460   mutable Selector autoreleaseS;
461   mutable Selector drainS;
462   mutable OwningPtr<BugType> BT;
463 
464 public:
465   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
466 };
467 }
468 
469 void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
470                                               CheckerContext &C) const {
471 
472   if (!BT) {
473     BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
474                            "instance"));
475 
476     ASTContext &Ctx = C.getASTContext();
477     releaseS = GetNullarySelector("release", Ctx);
478     retainS = GetNullarySelector("retain", Ctx);
479     autoreleaseS = GetNullarySelector("autorelease", Ctx);
480     drainS = GetNullarySelector("drain", Ctx);
481   }
482 
483   if (msg.isInstanceMessage())
484     return;
485   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
486   assert(Class);
487 
488   Selector S = msg.getSelector();
489   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
490     return;
491 
492   if (ExplodedNode *N = C.addTransition()) {
493     SmallString<200> buf;
494     llvm::raw_svector_ostream os(buf);
495 
496     os << "The '" << S.getAsString() << "' message should be sent to instances "
497           "of class '" << Class->getName()
498        << "' and not the class directly";
499 
500     BugReport *report = new BugReport(*BT, os.str(), N);
501     report->addRange(msg.getSourceRange());
502     C.emitReport(report);
503   }
504 }
505 
506 //===----------------------------------------------------------------------===//
507 // Check for passing non-Objective-C types to variadic methods that expect
508 // only Objective-C types.
509 //===----------------------------------------------------------------------===//
510 
511 namespace {
512 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
513   mutable Selector arrayWithObjectsS;
514   mutable Selector dictionaryWithObjectsAndKeysS;
515   mutable Selector setWithObjectsS;
516   mutable Selector orderedSetWithObjectsS;
517   mutable Selector initWithObjectsS;
518   mutable Selector initWithObjectsAndKeysS;
519   mutable OwningPtr<BugType> BT;
520 
521   bool isVariadicMessage(const ObjCMethodCall &msg) const;
522 
523 public:
524   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
525 };
526 }
527 
528 /// isVariadicMessage - Returns whether the given message is a variadic message,
529 /// where all arguments must be Objective-C types.
530 bool
531 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
532   const ObjCMethodDecl *MD = msg.getDecl();
533 
534   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
535     return false;
536 
537   Selector S = msg.getSelector();
538 
539   if (msg.isInstanceMessage()) {
540     // FIXME: Ideally we'd look at the receiver interface here, but that's not
541     // useful for init, because alloc returns 'id'. In theory, this could lead
542     // to false positives, for example if there existed a class that had an
543     // initWithObjects: implementation that does accept non-Objective-C pointer
544     // types, but the chance of that happening is pretty small compared to the
545     // gains that this analysis gives.
546     const ObjCInterfaceDecl *Class = MD->getClassInterface();
547 
548     switch (findKnownClass(Class)) {
549     case FC_NSArray:
550     case FC_NSOrderedSet:
551     case FC_NSSet:
552       return S == initWithObjectsS;
553     case FC_NSDictionary:
554       return S == initWithObjectsAndKeysS;
555     default:
556       return false;
557     }
558   } else {
559     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
560 
561     switch (findKnownClass(Class)) {
562       case FC_NSArray:
563         return S == arrayWithObjectsS;
564       case FC_NSOrderedSet:
565         return S == orderedSetWithObjectsS;
566       case FC_NSSet:
567         return S == setWithObjectsS;
568       case FC_NSDictionary:
569         return S == dictionaryWithObjectsAndKeysS;
570       default:
571         return false;
572     }
573   }
574 }
575 
576 void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
577                                                     CheckerContext &C) const {
578   if (!BT) {
579     BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
580                            "Objective-C pointer types"));
581 
582     ASTContext &Ctx = C.getASTContext();
583     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
584     dictionaryWithObjectsAndKeysS =
585       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
586     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
587     orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
588 
589     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
590     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
591   }
592 
593   if (!isVariadicMessage(msg))
594       return;
595 
596   // We are not interested in the selector arguments since they have
597   // well-defined types, so the compiler will issue a warning for them.
598   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
599 
600   // We're not interested in the last argument since it has to be nil or the
601   // compiler would have issued a warning for it elsewhere.
602   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
603 
604   if (variadicArgsEnd <= variadicArgsBegin)
605     return;
606 
607   // Verify that all arguments have Objective-C types.
608   llvm::Optional<ExplodedNode*> errorNode;
609   ProgramStateRef state = C.getState();
610 
611   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
612     QualType ArgTy = msg.getArgExpr(I)->getType();
613     if (ArgTy->isObjCObjectPointerType())
614       continue;
615 
616     // Block pointers are treaded as Objective-C pointers.
617     if (ArgTy->isBlockPointerType())
618       continue;
619 
620     // Ignore pointer constants.
621     if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
622       continue;
623 
624     // Ignore pointer types annotated with 'NSObject' attribute.
625     if (C.getASTContext().isObjCNSObjectType(ArgTy))
626       continue;
627 
628     // Ignore CF references, which can be toll-free bridged.
629     if (coreFoundation::isCFObjectRef(ArgTy))
630       continue;
631 
632     // Generate only one error node to use for all bug reports.
633     if (!errorNode.hasValue())
634       errorNode = C.addTransition();
635 
636     if (!errorNode.getValue())
637       continue;
638 
639     SmallString<128> sbuf;
640     llvm::raw_svector_ostream os(sbuf);
641 
642     StringRef TypeName = GetReceiverInterfaceName(msg);
643     if (!TypeName.empty())
644       os << "Argument to '" << TypeName << "' method '";
645     else
646       os << "Argument to method '";
647 
648     os << msg.getSelector().getAsString()
649        << "' should be an Objective-C pointer type, not '";
650     ArgTy.print(os, C.getLangOpts());
651     os << "'";
652 
653     BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
654     R->addRange(msg.getArgSourceRange(I));
655     C.emitReport(R);
656   }
657 }
658 
659 //===----------------------------------------------------------------------===//
660 // Improves the modeling of loops over Cocoa collections.
661 //===----------------------------------------------------------------------===//
662 
663 namespace {
664 class ObjCLoopChecker
665   : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
666 
667 public:
668   void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
669 };
670 }
671 
672 static bool isKnownNonNilCollectionType(QualType T) {
673   const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
674   if (!PT)
675     return false;
676 
677   const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
678   if (!ID)
679     return false;
680 
681   switch (findKnownClass(ID)) {
682   case FC_NSArray:
683   case FC_NSDictionary:
684   case FC_NSEnumerator:
685   case FC_NSOrderedSet:
686   case FC_NSSet:
687     return true;
688   default:
689     return false;
690   }
691 }
692 
693 void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
694                                     CheckerContext &C) const {
695   ProgramStateRef State = C.getState();
696 
697   // Check if this is the branch for the end of the loop.
698   SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
699   if (CollectionSentinel.isZeroConstant())
700     return;
701 
702   // See if the collection is one where we /know/ the elements are non-nil.
703   const Expr *Collection = FCS->getCollection();
704   if (!isKnownNonNilCollectionType(Collection->getType()))
705     return;
706 
707   // FIXME: Copied from ExprEngineObjC.
708   const Stmt *Element = FCS->getElement();
709   SVal ElementVar;
710   if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
711     const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
712     assert(ElemDecl->getInit() == 0);
713     ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
714   } else {
715     ElementVar = State->getSVal(Element, C.getLocationContext());
716   }
717 
718   if (!isa<Loc>(ElementVar))
719     return;
720 
721   // Go ahead and assume the value is non-nil.
722   SVal Val = State->getSVal(cast<Loc>(ElementVar));
723   State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
724   C.addTransition(State);
725 }
726 
727 namespace {
728 /// \class ObjCNonNilReturnValueChecker
729 /// \brief The checker restricts the return values of APIs known to
730 /// never (or almost never) return 'nil'.
731 class ObjCNonNilReturnValueChecker
732   : public Checker<check::PostObjCMessage> {
733     mutable bool Initialized;
734     mutable Selector ObjectAtIndex;
735     mutable Selector ObjectAtIndexedSubscript;
736 
737 public:
738   ObjCNonNilReturnValueChecker() : Initialized(false) {}
739   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
740 };
741 }
742 
743 static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
744                                            ProgramStateRef State,
745                                            CheckerContext &C) {
746   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
747   if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
748     return State->assume(*DV, true);
749   return State;
750 }
751 
752 void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
753                                                         CheckerContext &C)
754                                                         const {
755   ProgramStateRef State = C.getState();
756 
757   if (!Initialized) {
758     ASTContext &Ctx = C.getASTContext();
759     ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
760     ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
761   }
762 
763   // Check the receiver type.
764   if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
765 
766     // Assume that object returned from '[self init]' or '[super init]' is not
767     // 'nil' if we are processing an inlined function/method.
768     //
769     // A defensive callee will (and should) check if the object returned by
770     // '[super init]' is 'nil' before doing it's own initialization. However,
771     // since 'nil' is rarely returned in practice, we should not warn when the
772     // caller to the defensive constructor uses the object in contexts where
773     // 'nil' is not accepted.
774     if (!C.inTopFrame() && M.getDecl() &&
775         M.getDecl()->getMethodFamily() == OMF_init &&
776         M.isReceiverSelfOrSuper()) {
777       State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
778     }
779 
780     // Objects returned from
781     // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
782     // are never 'nil'.
783     FoundationClass Cl = findKnownClass(Interface);
784     if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
785       Selector Sel = M.getSelector();
786       if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
787         // Go ahead and assume the value is non-nil.
788         State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
789       }
790     }
791   }
792   C.addTransition(State);
793 }
794 
795 //===----------------------------------------------------------------------===//
796 // Check registration.
797 //===----------------------------------------------------------------------===//
798 
799 void ento::registerNilArgChecker(CheckerManager &mgr) {
800   mgr.registerChecker<NilArgChecker>();
801 }
802 
803 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
804   mgr.registerChecker<CFNumberCreateChecker>();
805 }
806 
807 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
808   mgr.registerChecker<CFRetainReleaseChecker>();
809 }
810 
811 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
812   mgr.registerChecker<ClassReleaseChecker>();
813 }
814 
815 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
816   mgr.registerChecker<VariadicMethodTypeChecker>();
817 }
818 
819 void ento::registerObjCLoopChecker(CheckerManager &mgr) {
820   mgr.registerChecker<ObjCLoopChecker>();
821 }
822 
823 void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
824   mgr.registerChecker<ObjCNonNilReturnValueChecker>();
825 }
826