• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines BasicObjCFoundationChecks, a class that encapsulates
11 //  a set of simple checks to run on Objective-C code using Apple's Foundation
12 //  classes.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "ClangSACheckers.h"
17 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
18 #include "clang/StaticAnalyzer/Core/Checker.h"
19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
24 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
26 #include "clang/AST/DeclObjC.h"
27 #include "clang/AST/Expr.h"
28 #include "clang/AST/ExprObjC.h"
29 #include "clang/AST/ASTContext.h"
30 
31 using namespace clang;
32 using namespace ento;
33 
34 namespace {
35 class APIMisuse : public BugType {
36 public:
APIMisuse(const char * name)37   APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
38 };
39 } // end anonymous namespace
40 
41 //===----------------------------------------------------------------------===//
42 // Utility functions.
43 //===----------------------------------------------------------------------===//
44 
GetReceiverNameType(const ObjCMessage & msg)45 static const char* GetReceiverNameType(const ObjCMessage &msg) {
46   if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
47     return ID->getIdentifier()->getNameStart();
48   return 0;
49 }
50 
isReceiverClassOrSuperclass(const ObjCInterfaceDecl * ID,llvm::StringRef ClassName)51 static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
52                                         llvm::StringRef ClassName) {
53   if (ID->getIdentifier()->getName() == ClassName)
54     return true;
55 
56   if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
57     return isReceiverClassOrSuperclass(Super, ClassName);
58 
59   return false;
60 }
61 
isNil(SVal X)62 static inline bool isNil(SVal X) {
63   return isa<loc::ConcreteInt>(X);
64 }
65 
66 //===----------------------------------------------------------------------===//
67 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
68 //===----------------------------------------------------------------------===//
69 
70 namespace {
71   class NilArgChecker : public Checker<check::PreObjCMessage> {
72     mutable llvm::OwningPtr<APIMisuse> BT;
73 
74     void WarnNilArg(CheckerContext &C,
75                     const ObjCMessage &msg, unsigned Arg) const;
76 
77   public:
78     void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
79   };
80 }
81 
WarnNilArg(CheckerContext & C,const ObjCMessage & msg,unsigned int Arg) const82 void NilArgChecker::WarnNilArg(CheckerContext &C,
83                                const ObjCMessage &msg,
84                                unsigned int Arg) const
85 {
86   if (!BT)
87     BT.reset(new APIMisuse("nil argument"));
88 
89   if (ExplodedNode *N = C.generateSink()) {
90     llvm::SmallString<128> sbuf;
91     llvm::raw_svector_ostream os(sbuf);
92     os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
93        << msg.getSelector().getAsString() << "' cannot be nil";
94 
95     RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
96     R->addRange(msg.getArgSourceRange(Arg));
97     C.EmitReport(R);
98   }
99 }
100 
checkPreObjCMessage(ObjCMessage msg,CheckerContext & C) const101 void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
102                                         CheckerContext &C) const {
103   const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
104   if (!ID)
105     return;
106 
107   if (isReceiverClassOrSuperclass(ID, "NSString")) {
108     Selector S = msg.getSelector();
109 
110     if (S.isUnarySelector())
111       return;
112 
113     // FIXME: This is going to be really slow doing these checks with
114     //  lexical comparisons.
115 
116     std::string NameStr = S.getAsString();
117     llvm::StringRef Name(NameStr);
118     assert(!Name.empty());
119 
120     // FIXME: Checking for initWithFormat: will not work in most cases
121     //  yet because [NSString alloc] returns id, not NSString*.  We will
122     //  need support for tracking expected-type information in the analyzer
123     //  to find these errors.
124     if (Name == "caseInsensitiveCompare:" ||
125         Name == "compare:" ||
126         Name == "compare:options:" ||
127         Name == "compare:options:range:" ||
128         Name == "compare:options:range:locale:" ||
129         Name == "componentsSeparatedByCharactersInSet:" ||
130         Name == "initWithFormat:") {
131       if (isNil(msg.getArgSVal(0, C.getState())))
132         WarnNilArg(C, msg, 0);
133     }
134   }
135 }
136 
137 //===----------------------------------------------------------------------===//
138 // Error reporting.
139 //===----------------------------------------------------------------------===//
140 
141 namespace {
142 class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
143   mutable llvm::OwningPtr<APIMisuse> BT;
144   mutable IdentifierInfo* II;
145 public:
CFNumberCreateChecker()146   CFNumberCreateChecker() : II(0) {}
147 
148   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
149 
150 private:
151   void EmitError(const TypedRegion* R, const Expr* Ex,
152                 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
153 };
154 } // end anonymous namespace
155 
156 enum CFNumberType {
157   kCFNumberSInt8Type = 1,
158   kCFNumberSInt16Type = 2,
159   kCFNumberSInt32Type = 3,
160   kCFNumberSInt64Type = 4,
161   kCFNumberFloat32Type = 5,
162   kCFNumberFloat64Type = 6,
163   kCFNumberCharType = 7,
164   kCFNumberShortType = 8,
165   kCFNumberIntType = 9,
166   kCFNumberLongType = 10,
167   kCFNumberLongLongType = 11,
168   kCFNumberFloatType = 12,
169   kCFNumberDoubleType = 13,
170   kCFNumberCFIndexType = 14,
171   kCFNumberNSIntegerType = 15,
172   kCFNumberCGFloatType = 16
173 };
174 
175 namespace {
176   template<typename T>
177   class Optional {
178     bool IsKnown;
179     T Val;
180   public:
Optional()181     Optional() : IsKnown(false), Val(0) {}
Optional(const T & val)182     Optional(const T& val) : IsKnown(true), Val(val) {}
183 
isKnown() const184     bool isKnown() const { return IsKnown; }
185 
getValue() const186     const T& getValue() const {
187       assert (isKnown());
188       return Val;
189     }
190 
operator const T&() const191     operator const T&() const {
192       return getValue();
193     }
194   };
195 }
196 
GetCFNumberSize(ASTContext & Ctx,uint64_t i)197 static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
198   static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
199 
200   if (i < kCFNumberCharType)
201     return FixedSize[i-1];
202 
203   QualType T;
204 
205   switch (i) {
206     case kCFNumberCharType:     T = Ctx.CharTy;     break;
207     case kCFNumberShortType:    T = Ctx.ShortTy;    break;
208     case kCFNumberIntType:      T = Ctx.IntTy;      break;
209     case kCFNumberLongType:     T = Ctx.LongTy;     break;
210     case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
211     case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
212     case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
213     case kCFNumberCFIndexType:
214     case kCFNumberNSIntegerType:
215     case kCFNumberCGFloatType:
216       // FIXME: We need a way to map from names to Type*.
217     default:
218       return Optional<uint64_t>();
219   }
220 
221   return Ctx.getTypeSize(T);
222 }
223 
224 #if 0
225 static const char* GetCFNumberTypeStr(uint64_t i) {
226   static const char* Names[] = {
227     "kCFNumberSInt8Type",
228     "kCFNumberSInt16Type",
229     "kCFNumberSInt32Type",
230     "kCFNumberSInt64Type",
231     "kCFNumberFloat32Type",
232     "kCFNumberFloat64Type",
233     "kCFNumberCharType",
234     "kCFNumberShortType",
235     "kCFNumberIntType",
236     "kCFNumberLongType",
237     "kCFNumberLongLongType",
238     "kCFNumberFloatType",
239     "kCFNumberDoubleType",
240     "kCFNumberCFIndexType",
241     "kCFNumberNSIntegerType",
242     "kCFNumberCGFloatType"
243   };
244 
245   return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
246 }
247 #endif
248 
checkPreStmt(const CallExpr * CE,CheckerContext & C) const249 void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
250                                          CheckerContext &C) const {
251   const Expr* Callee = CE->getCallee();
252   const GRState *state = C.getState();
253   SVal CallV = state->getSVal(Callee);
254   const FunctionDecl* FD = CallV.getAsFunctionDecl();
255 
256   if (!FD)
257     return;
258 
259   ASTContext &Ctx = C.getASTContext();
260   if (!II)
261     II = &Ctx.Idents.get("CFNumberCreate");
262 
263   if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
264     return;
265 
266   // Get the value of the "theType" argument.
267   SVal TheTypeVal = state->getSVal(CE->getArg(1));
268 
269   // FIXME: We really should allow ranges of valid theType values, and
270   //   bifurcate the state appropriately.
271   nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
272   if (!V)
273     return;
274 
275   uint64_t NumberKind = V->getValue().getLimitedValue();
276   Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
277 
278   // FIXME: In some cases we can emit an error.
279   if (!TargetSize.isKnown())
280     return;
281 
282   // Look at the value of the integer being passed by reference.  Essentially
283   // we want to catch cases where the value passed in is not equal to the
284   // size of the type being created.
285   SVal TheValueExpr = state->getSVal(CE->getArg(2));
286 
287   // FIXME: Eventually we should handle arbitrary locations.  We can do this
288   //  by having an enhanced memory model that does low-level typing.
289   loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
290   if (!LV)
291     return;
292 
293   const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts());
294   if (!R)
295     return;
296 
297   QualType T = Ctx.getCanonicalType(R->getValueType());
298 
299   // FIXME: If the pointee isn't an integer type, should we flag a warning?
300   //  People can do weird stuff with pointers.
301 
302   if (!T->isIntegerType())
303     return;
304 
305   uint64_t SourceSize = Ctx.getTypeSize(T);
306 
307   // CHECK: is SourceSize == TargetSize
308   if (SourceSize == TargetSize)
309     return;
310 
311   // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
312   // otherwise generate a regular node.
313   //
314   // FIXME: We can actually create an abstract "CFNumber" object that has
315   //  the bits initialized to the provided values.
316   //
317   if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
318                                                 : C.generateNode()) {
319     llvm::SmallString<128> sbuf;
320     llvm::raw_svector_ostream os(sbuf);
321 
322     os << (SourceSize == 8 ? "An " : "A ")
323        << SourceSize << " bit integer is used to initialize a CFNumber "
324                         "object that represents "
325        << (TargetSize == 8 ? "an " : "a ")
326        << TargetSize << " bit integer. ";
327 
328     if (SourceSize < TargetSize)
329       os << (TargetSize - SourceSize)
330       << " bits of the CFNumber value will be garbage." ;
331     else
332       os << (SourceSize - TargetSize)
333       << " bits of the input integer will be lost.";
334 
335     if (!BT)
336       BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
337 
338     RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
339     report->addRange(CE->getArg(2)->getSourceRange());
340     C.EmitReport(report);
341   }
342 }
343 
344 //===----------------------------------------------------------------------===//
345 // CFRetain/CFRelease checking for null arguments.
346 //===----------------------------------------------------------------------===//
347 
348 namespace {
349 class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
350   mutable llvm::OwningPtr<APIMisuse> BT;
351   mutable IdentifierInfo *Retain, *Release;
352 public:
CFRetainReleaseChecker()353   CFRetainReleaseChecker(): Retain(0), Release(0) {}
354   void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
355 };
356 } // end anonymous namespace
357 
358 
checkPreStmt(const CallExpr * CE,CheckerContext & C) const359 void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
360                                           CheckerContext& C) const {
361   // If the CallExpr doesn't have exactly 1 argument just give up checking.
362   if (CE->getNumArgs() != 1)
363     return;
364 
365   // Get the function declaration of the callee.
366   const GRState* state = C.getState();
367   SVal X = state->getSVal(CE->getCallee());
368   const FunctionDecl* FD = X.getAsFunctionDecl();
369 
370   if (!FD)
371     return;
372 
373   if (!BT) {
374     ASTContext &Ctx = C.getASTContext();
375     Retain = &Ctx.Idents.get("CFRetain");
376     Release = &Ctx.Idents.get("CFRelease");
377     BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
378   }
379 
380   // Check if we called CFRetain/CFRelease.
381   const IdentifierInfo *FuncII = FD->getIdentifier();
382   if (!(FuncII == Retain || FuncII == Release))
383     return;
384 
385   // FIXME: The rest of this just checks that the argument is non-null.
386   // It should probably be refactored and combined with AttrNonNullChecker.
387 
388   // Get the argument's value.
389   const Expr *Arg = CE->getArg(0);
390   SVal ArgVal = state->getSVal(Arg);
391   DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
392   if (!DefArgVal)
393     return;
394 
395   // Get a NULL value.
396   SValBuilder &svalBuilder = C.getSValBuilder();
397   DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
398 
399   // Make an expression asserting that they're equal.
400   DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
401 
402   // Are they equal?
403   const GRState *stateTrue, *stateFalse;
404   llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
405 
406   if (stateTrue && !stateFalse) {
407     ExplodedNode *N = C.generateSink(stateTrue);
408     if (!N)
409       return;
410 
411     const char *description = (FuncII == Retain)
412                             ? "Null pointer argument in call to CFRetain"
413                             : "Null pointer argument in call to CFRelease";
414 
415     EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
416     report->addRange(Arg->getSourceRange());
417     report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
418     C.EmitReport(report);
419     return;
420   }
421 
422   // From here on, we know the argument is non-null.
423   C.addTransition(stateFalse);
424 }
425 
426 //===----------------------------------------------------------------------===//
427 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
428 //===----------------------------------------------------------------------===//
429 
430 namespace {
431 class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
432   mutable Selector releaseS;
433   mutable Selector retainS;
434   mutable Selector autoreleaseS;
435   mutable Selector drainS;
436   mutable llvm::OwningPtr<BugType> BT;
437 
438 public:
439   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
440 };
441 }
442 
checkPreObjCMessage(ObjCMessage msg,CheckerContext & C) const443 void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
444                                               CheckerContext &C) const {
445 
446   if (!BT) {
447     BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
448                            "instance"));
449 
450     ASTContext &Ctx = C.getASTContext();
451     releaseS = GetNullarySelector("release", Ctx);
452     retainS = GetNullarySelector("retain", Ctx);
453     autoreleaseS = GetNullarySelector("autorelease", Ctx);
454     drainS = GetNullarySelector("drain", Ctx);
455   }
456 
457   if (msg.isInstanceMessage())
458     return;
459   const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
460   assert(Class);
461 
462   Selector S = msg.getSelector();
463   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
464     return;
465 
466   if (ExplodedNode *N = C.generateNode()) {
467     llvm::SmallString<200> buf;
468     llvm::raw_svector_ostream os(buf);
469 
470     os << "The '" << S.getAsString() << "' message should be sent to instances "
471           "of class '" << Class->getName()
472        << "' and not the class directly";
473 
474     RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
475     report->addRange(msg.getSourceRange());
476     C.EmitReport(report);
477   }
478 }
479 
480 //===----------------------------------------------------------------------===//
481 // Check for passing non-Objective-C types to variadic methods that expect
482 // only Objective-C types.
483 //===----------------------------------------------------------------------===//
484 
485 namespace {
486 class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
487   mutable Selector arrayWithObjectsS;
488   mutable Selector dictionaryWithObjectsAndKeysS;
489   mutable Selector setWithObjectsS;
490   mutable Selector initWithObjectsS;
491   mutable Selector initWithObjectsAndKeysS;
492   mutable llvm::OwningPtr<BugType> BT;
493 
494   bool isVariadicMessage(const ObjCMessage &msg) const;
495 
496 public:
497   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
498 };
499 }
500 
501 /// isVariadicMessage - Returns whether the given message is a variadic message,
502 /// where all arguments must be Objective-C types.
503 bool
isVariadicMessage(const ObjCMessage & msg) const504 VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
505   const ObjCMethodDecl *MD = msg.getMethodDecl();
506 
507   if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
508     return false;
509 
510   Selector S = msg.getSelector();
511 
512   if (msg.isInstanceMessage()) {
513     // FIXME: Ideally we'd look at the receiver interface here, but that's not
514     // useful for init, because alloc returns 'id'. In theory, this could lead
515     // to false positives, for example if there existed a class that had an
516     // initWithObjects: implementation that does accept non-Objective-C pointer
517     // types, but the chance of that happening is pretty small compared to the
518     // gains that this analysis gives.
519     const ObjCInterfaceDecl *Class = MD->getClassInterface();
520 
521     // -[NSArray initWithObjects:]
522     if (isReceiverClassOrSuperclass(Class, "NSArray") &&
523         S == initWithObjectsS)
524       return true;
525 
526     // -[NSDictionary initWithObjectsAndKeys:]
527     if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
528         S == initWithObjectsAndKeysS)
529       return true;
530 
531     // -[NSSet initWithObjects:]
532     if (isReceiverClassOrSuperclass(Class, "NSSet") &&
533         S == initWithObjectsS)
534       return true;
535   } else {
536     const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
537 
538     // -[NSArray arrayWithObjects:]
539     if (isReceiverClassOrSuperclass(Class, "NSArray") &&
540         S == arrayWithObjectsS)
541       return true;
542 
543     // -[NSDictionary dictionaryWithObjectsAndKeys:]
544     if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
545         S == dictionaryWithObjectsAndKeysS)
546       return true;
547 
548     // -[NSSet setWithObjects:]
549     if (isReceiverClassOrSuperclass(Class, "NSSet") &&
550         S == setWithObjectsS)
551       return true;
552   }
553 
554   return false;
555 }
556 
checkPreObjCMessage(ObjCMessage msg,CheckerContext & C) const557 void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
558                                                     CheckerContext &C) const {
559   if (!BT) {
560     BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
561                            "Objective-C pointer types"));
562 
563     ASTContext &Ctx = C.getASTContext();
564     arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
565     dictionaryWithObjectsAndKeysS =
566       GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
567     setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
568 
569     initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
570     initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
571   }
572 
573   if (!isVariadicMessage(msg))
574       return;
575 
576   // We are not interested in the selector arguments since they have
577   // well-defined types, so the compiler will issue a warning for them.
578   unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
579 
580   // We're not interested in the last argument since it has to be nil or the
581   // compiler would have issued a warning for it elsewhere.
582   unsigned variadicArgsEnd = msg.getNumArgs() - 1;
583 
584   if (variadicArgsEnd <= variadicArgsBegin)
585     return;
586 
587   // Verify that all arguments have Objective-C types.
588   llvm::Optional<ExplodedNode*> errorNode;
589   const GRState *state = C.getState();
590 
591   for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
592     QualType ArgTy = msg.getArgType(I);
593     if (ArgTy->isObjCObjectPointerType())
594       continue;
595 
596     // Block pointers are treaded as Objective-C pointers.
597     if (ArgTy->isBlockPointerType())
598       continue;
599 
600     // Ignore pointer constants.
601     if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
602       continue;
603 
604     // Ignore pointer types annotated with 'NSObject' attribute.
605     if (C.getASTContext().isObjCNSObjectType(ArgTy))
606       continue;
607 
608     // Ignore CF references, which can be toll-free bridged.
609     if (coreFoundation::isCFObjectRef(ArgTy))
610       continue;
611 
612     // Generate only one error node to use for all bug reports.
613     if (!errorNode.hasValue()) {
614       errorNode = C.generateNode();
615     }
616 
617     if (!errorNode.getValue())
618       continue;
619 
620     llvm::SmallString<128> sbuf;
621     llvm::raw_svector_ostream os(sbuf);
622 
623     if (const char *TypeName = GetReceiverNameType(msg))
624       os << "Argument to '" << TypeName << "' method '";
625     else
626       os << "Argument to method '";
627 
628     os << msg.getSelector().getAsString()
629       << "' should be an Objective-C pointer type, not '"
630       << ArgTy.getAsString() << "'";
631 
632     RangedBugReport *R = new RangedBugReport(*BT, os.str(),
633                                              errorNode.getValue());
634     R->addRange(msg.getArgSourceRange(I));
635     C.EmitReport(R);
636   }
637 }
638 
639 //===----------------------------------------------------------------------===//
640 // Check registration.
641 //===----------------------------------------------------------------------===//
642 
registerNilArgChecker(CheckerManager & mgr)643 void ento::registerNilArgChecker(CheckerManager &mgr) {
644   mgr.registerChecker<NilArgChecker>();
645 }
646 
registerCFNumberCreateChecker(CheckerManager & mgr)647 void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
648   mgr.registerChecker<CFNumberCreateChecker>();
649 }
650 
registerCFRetainReleaseChecker(CheckerManager & mgr)651 void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
652   mgr.registerChecker<CFRetainReleaseChecker>();
653 }
654 
registerClassReleaseChecker(CheckerManager & mgr)655 void ento::registerClassReleaseChecker(CheckerManager &mgr) {
656   mgr.registerChecker<ClassReleaseChecker>();
657 }
658 
registerVariadicMethodTypeChecker(CheckerManager & mgr)659 void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
660   mgr.registerChecker<VariadicMethodTypeChecker>();
661 }
662