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