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