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