blob: aa85769157e7acb7496495d9a0ab0fa146ee31bc [file] [log] [blame]
Ted Kremenekb0a2e472008-03-27 07:25:52 +00001//== 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
Ted Kremenek7a681942008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Ted Kremenekb0a2e472008-03-27 07:25:52 +000018#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
Ted Kremenek9f20c7c2008-07-22 16:21:24 +000020#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenekabd89ac2008-08-13 04:27:00 +000021#include "clang/Analysis/PathSensitive/GRState.h"
Ted Kremenekf00daf02008-04-03 17:57:38 +000022#include "clang/Analysis/PathSensitive/BugReporter.h"
Ted Kremenekb15eba42008-10-04 05:50:14 +000023#include "clang/Analysis/PathSensitive/MemRegion.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000024#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek9f20c7c2008-07-22 16:21:24 +000025#include "clang/Analysis/LocalCheckers.h"
Daniel Dunbar64789f82008-08-11 05:35:13 +000026#include "clang/AST/DeclObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000027#include "clang/AST/Expr.h"
Steve Naroff9ed3e772008-05-29 21:12:08 +000028#include "clang/AST/ExprObjC.h"
Ted Kremenekb0a2e472008-03-27 07:25:52 +000029#include "clang/AST/ASTContext.h"
30#include "llvm/Support/Compiler.h"
31
Ted Kremenekb0a2e472008-03-27 07:25:52 +000032using namespace clang;
Ted Kremenek7a681942008-03-27 17:17:22 +000033
Ted Kremenek639247a2008-03-27 22:05:32 +000034static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
35 Expr* Receiver = ME->getReceiver();
36
37 if (!Receiver)
38 return NULL;
39
Ted Kremenek92c78b62008-04-03 21:44:24 +000040 QualType X = Receiver->getType();
Ted Kremenekbfc6cce2008-04-19 19:12:50 +000041
Ted Kremenekd810bf82008-04-30 22:48:21 +000042 if (X->isPointerType()) {
43 Type* TP = X.getTypePtr();
44 const PointerType* T = TP->getAsPointerType();
45 return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
46 }
47
48 // FIXME: Support ObjCQualifiedIdType?
49 return NULL;
Ted Kremenek639247a2008-03-27 22:05:32 +000050}
51
52static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
53 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
54 return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
55 : NULL;
56}
Ted Kremenek7a681942008-03-27 17:17:22 +000057
Ted Kremenekf00daf02008-04-03 17:57:38 +000058namespace {
Ted Kremenek5fd0e672008-09-21 19:01:39 +000059
Ted Kremenekbf6babf2009-02-04 23:49:09 +000060class VISIBILITY_HIDDEN APIMisuse : public BugType {
Ted Kremenekf00daf02008-04-03 17:57:38 +000061public:
Ted Kremenekbf6babf2009-02-04 23:49:09 +000062 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
Ted Kremenekf00daf02008-04-03 17:57:38 +000063};
Ted Kremenekf00daf02008-04-03 17:57:38 +000064
65class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
Ted Kremenekbf6babf2009-02-04 23:49:09 +000066 APIMisuse *BT;
67 BugReporter& BR;
Ted Kremenekf00daf02008-04-03 17:57:38 +000068 ASTContext &Ctx;
Ted Kremenekf00daf02008-04-03 17:57:38 +000069
70 bool isNSString(ObjCInterfaceType* T, const char* suffix);
71 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
72
73 void Warn(NodeTy* N, Expr* E, const std::string& s);
74 void WarnNilArg(NodeTy* N, Expr* E);
75
76 bool CheckNilArg(NodeTy* N, unsigned Arg);
77
78public:
Ted Kremenekc0cccca2009-06-18 23:58:37 +000079 BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br)
80 : BT(0), BR(br), Ctx(ctx) {}
Ted Kremenekbf6babf2009-02-04 23:49:09 +000081
82 bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf00daf02008-04-03 17:57:38 +000083
Ted Kremenekbf6babf2009-02-04 23:49:09 +000084private:
85 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
86 std::string sbuf;
87 llvm::raw_string_ostream os(sbuf);
88 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
89 << ME->getSelector().getAsString() << "' cannot be nil.";
90
91 // Lazily create the BugType object for NilArg. This will be owned
92 // by the BugReporter object 'BR' once we call BR.EmitWarning.
93 if (!BT) BT = new APIMisuse("nil argument");
94
95 RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
96 R->addRange(ME->getArg(Arg)->getSourceRange());
97 BR.EmitReport(R);
Ted Kremenekf00daf02008-04-03 17:57:38 +000098 }
99};
100
101} // end anonymous namespace
102
103
104GRSimpleAPICheck*
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000105clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) {
106 return new BasicObjCFoundationChecks(Ctx, BR);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000107}
108
109
110
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000111bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
112 GRStateManager&) {
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000113
114 ObjCMessageExpr* ME =
115 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000116
Ted Kremenek639247a2008-03-27 22:05:32 +0000117 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000118
119 if (!ReceiverType)
Nuno Lopesf44f0932008-05-20 17:33:56 +0000120 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000121
Ted Kremenek639247a2008-03-27 22:05:32 +0000122 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
123
124 if (!name)
125 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000126
127 if (name[0] != 'N' || name[1] != 'S')
128 return false;
129
130 name += 2;
131
132 // FIXME: Make all of this faster.
133
134 if (isNSString(ReceiverType, name))
135 return AuditNSString(N, ME);
136
Nuno Lopesf44f0932008-05-20 17:33:56 +0000137 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000138}
139
Zhongxing Xu097fc982008-10-17 05:57:07 +0000140static inline bool isNil(SVal X) {
141 return isa<loc::ConcreteInt>(X);
Ted Kremenek583c4382008-03-27 21:15:17 +0000142}
143
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000144//===----------------------------------------------------------------------===//
145// Error reporting.
146//===----------------------------------------------------------------------===//
147
Ted Kremenek639247a2008-03-27 22:05:32 +0000148bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
149 ObjCMessageExpr* ME =
150 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
151
152 Expr * E = ME->getArg(Arg);
153
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000154 if (isNil(N->getState()->getSVal(E))) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000155 WarnNilArg(N, ME, Arg);
Ted Kremenek639247a2008-03-27 22:05:32 +0000156 return true;
157 }
158
159 return false;
160}
161
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000162//===----------------------------------------------------------------------===//
163// NSString checking.
164//===----------------------------------------------------------------------===//
165
166bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
167 const char* suffix) {
168
169 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
170}
171
172bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
173 ObjCMessageExpr* ME) {
174
175 Selector S = ME->getSelector();
176
177 if (S.isUnarySelector())
178 return false;
179
180 // FIXME: This is going to be really slow doing these checks with
181 // lexical comparisons.
182
Chris Lattner3a8f2942008-11-24 03:33:13 +0000183 std::string name = S.getAsString();
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000184 assert (!name.empty());
185 const char* cstr = &name[0];
186 unsigned len = name.size();
Ted Kremenek639247a2008-03-27 22:05:32 +0000187
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000188 switch (len) {
189 default:
190 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000191 case 8:
Ted Kremenek639247a2008-03-27 22:05:32 +0000192 if (!strcmp(cstr, "compare:"))
193 return CheckNilArg(N, 0);
194
195 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000196
197 case 15:
198 // FIXME: Checking for initWithFormat: will not work in most cases
199 // yet because [NSString alloc] returns id, not NSString*. We will
200 // need support for tracking expected-type information in the analyzer
201 // to find these errors.
202 if (!strcmp(cstr, "initWithFormat:"))
203 return CheckNilArg(N, 0);
204
205 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000206
Ted Kremenek639247a2008-03-27 22:05:32 +0000207 case 16:
208 if (!strcmp(cstr, "compare:options:"))
209 return CheckNilArg(N, 0);
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000210
211 break;
Ted Kremenek639247a2008-03-27 22:05:32 +0000212
213 case 22:
214 if (!strcmp(cstr, "compare:options:range:"))
215 return CheckNilArg(N, 0);
216
217 break;
218
219 case 23:
220
221 if (!strcmp(cstr, "caseInsensitiveCompare:"))
222 return CheckNilArg(N, 0);
223
224 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000225
Ted Kremenek639247a2008-03-27 22:05:32 +0000226 case 29:
227 if (!strcmp(cstr, "compare:options:range:locale:"))
228 return CheckNilArg(N, 0);
229
230 break;
231
232 case 37:
233 if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
234 return CheckNilArg(N, 0);
235
236 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000237 }
238
239 return false;
240}
Ted Kremenekc1290552008-06-26 23:59:48 +0000241
242//===----------------------------------------------------------------------===//
243// Error reporting.
244//===----------------------------------------------------------------------===//
245
246namespace {
Ted Kremenekc1290552008-06-26 23:59:48 +0000247
Ted Kremenekc1290552008-06-26 23:59:48 +0000248class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000249 APIMisuse* BT;
Ted Kremenekc1290552008-06-26 23:59:48 +0000250
251 // FIXME: Either this should be refactored into GRSimpleAPICheck, or
252 // it should always be passed with a call to Audit. The latter
253 // approach makes this class more stateless.
254 ASTContext& Ctx;
255 IdentifierInfo* II;
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000256 BugReporter& BR;
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000257
Ted Kremenekc1290552008-06-26 23:59:48 +0000258public:
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000259 AuditCFNumberCreate(ASTContext& ctx, BugReporter& br)
260 : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){}
Ted Kremenekc1290552008-06-26 23:59:48 +0000261
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000262 ~AuditCFNumberCreate() {}
Ted Kremenekc1290552008-06-26 23:59:48 +0000263
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000264 bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekc1290552008-06-26 23:59:48 +0000265
266private:
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000267 void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000268 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
269};
270} // end anonymous namespace
271
272enum CFNumberType {
273 kCFNumberSInt8Type = 1,
274 kCFNumberSInt16Type = 2,
275 kCFNumberSInt32Type = 3,
276 kCFNumberSInt64Type = 4,
277 kCFNumberFloat32Type = 5,
278 kCFNumberFloat64Type = 6,
279 kCFNumberCharType = 7,
280 kCFNumberShortType = 8,
281 kCFNumberIntType = 9,
282 kCFNumberLongType = 10,
283 kCFNumberLongLongType = 11,
284 kCFNumberFloatType = 12,
285 kCFNumberDoubleType = 13,
286 kCFNumberCFIndexType = 14,
287 kCFNumberNSIntegerType = 15,
288 kCFNumberCGFloatType = 16
289};
290
291namespace {
292 template<typename T>
293 class Optional {
294 bool IsKnown;
295 T Val;
296 public:
297 Optional() : IsKnown(false), Val(0) {}
298 Optional(const T& val) : IsKnown(true), Val(val) {}
299
300 bool isKnown() const { return IsKnown; }
301
302 const T& getValue() const {
303 assert (isKnown());
304 return Val;
305 }
306
307 operator const T&() const {
308 return getValue();
309 }
310 };
311}
312
313static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
314 static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
315
316 if (i < kCFNumberCharType)
317 return FixedSize[i-1];
318
319 QualType T;
320
321 switch (i) {
322 case kCFNumberCharType: T = Ctx.CharTy; break;
323 case kCFNumberShortType: T = Ctx.ShortTy; break;
324 case kCFNumberIntType: T = Ctx.IntTy; break;
325 case kCFNumberLongType: T = Ctx.LongTy; break;
326 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
327 case kCFNumberFloatType: T = Ctx.FloatTy; break;
328 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
329 case kCFNumberCFIndexType:
330 case kCFNumberNSIntegerType:
331 case kCFNumberCGFloatType:
332 // FIXME: We need a way to map from names to Type*.
333 default:
334 return Optional<uint64_t>();
335 }
336
337 return Ctx.getTypeSize(T);
338}
339
340#if 0
341static const char* GetCFNumberTypeStr(uint64_t i) {
342 static const char* Names[] = {
343 "kCFNumberSInt8Type",
344 "kCFNumberSInt16Type",
345 "kCFNumberSInt32Type",
346 "kCFNumberSInt64Type",
347 "kCFNumberFloat32Type",
348 "kCFNumberFloat64Type",
349 "kCFNumberCharType",
350 "kCFNumberShortType",
351 "kCFNumberIntType",
352 "kCFNumberLongType",
353 "kCFNumberLongLongType",
354 "kCFNumberFloatType",
355 "kCFNumberDoubleType",
356 "kCFNumberCFIndexType",
357 "kCFNumberNSIntegerType",
358 "kCFNumberCGFloatType"
359 };
360
361 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
362}
363#endif
364
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000365bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenekc1290552008-06-26 23:59:48 +0000366 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
367 Expr* Callee = CE->getCallee();
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000368 SVal CallV = N->getState()->getSVal(Callee);
Zhongxing Xucac107a2009-04-20 05:24:46 +0000369 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenekc1290552008-06-26 23:59:48 +0000370
Zhongxing Xucac107a2009-04-20 05:24:46 +0000371 if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
Ted Kremenekc1290552008-06-26 23:59:48 +0000372 return false;
373
374 // Get the value of the "theType" argument.
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000375 SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1));
Ted Kremenekc1290552008-06-26 23:59:48 +0000376
377 // FIXME: We really should allow ranges of valid theType values, and
378 // bifurcate the state appropriately.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000379 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekc1290552008-06-26 23:59:48 +0000380
381 if (!V)
382 return false;
383
384 uint64_t NumberKind = V->getValue().getLimitedValue();
385 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
386
387 // FIXME: In some cases we can emit an error.
388 if (!TargetSize.isKnown())
389 return false;
390
391 // Look at the value of the integer being passed by reference. Essentially
392 // we want to catch cases where the value passed in is not equal to the
393 // size of the type being created.
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000394 SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2));
Ted Kremenekc1290552008-06-26 23:59:48 +0000395
396 // FIXME: Eventually we should handle arbitrary locations. We can do this
397 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000398 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekc1290552008-06-26 23:59:48 +0000399
400 if (!LV)
401 return false;
402
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000403 const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
Ted Kremenekf5da3252008-12-13 21:49:13 +0000404 if (!R) return false;
Ted Kremenekb15eba42008-10-04 05:50:14 +0000405
Ted Kremenek6a9b5352009-03-01 05:44:08 +0000406 while (const TypedViewRegion* ATR = dyn_cast<TypedViewRegion>(R)) {
Ted Kremenekf5da3252008-12-13 21:49:13 +0000407 R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
408 if (!R) return false;
409 }
Ted Kremenekb15eba42008-10-04 05:50:14 +0000410
Zhongxing Xu20362702009-05-09 03:57:34 +0000411 QualType T = Ctx.getCanonicalType(R->getValueType(Ctx));
Ted Kremenekc1290552008-06-26 23:59:48 +0000412
413 // FIXME: If the pointee isn't an integer type, should we flag a warning?
414 // People can do weird stuff with pointers.
415
416 if (!T->isIntegerType())
417 return false;
418
419 uint64_t SourceSize = Ctx.getTypeSize(T);
420
421 // CHECK: is SourceSize == TargetSize
422
423 if (SourceSize == TargetSize)
424 return false;
425
Ted Kremenekb15eba42008-10-04 05:50:14 +0000426 AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
Ted Kremenekc1290552008-06-26 23:59:48 +0000427
428 // FIXME: We can actually create an abstract "CFNumber" object that has
429 // the bits initialized to the provided values.
430 return SourceSize < TargetSize;
431}
432
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000433void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000434 ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000435 uint64_t SourceSize, uint64_t TargetSize,
436 uint64_t NumberKind) {
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000437
438 std::string sbuf;
439 llvm::raw_string_ostream os(sbuf);
Ted Kremenekc1290552008-06-26 23:59:48 +0000440
441 os << (SourceSize == 8 ? "An " : "A ")
442 << SourceSize << " bit integer is used to initialize a CFNumber "
443 "object that represents "
444 << (TargetSize == 8 ? "an " : "a ")
445 << TargetSize << " bit integer. ";
446
447 if (SourceSize < TargetSize)
448 os << (TargetSize - SourceSize)
449 << " bits of the CFNumber value will be garbage." ;
450 else
451 os << (SourceSize - TargetSize)
452 << " bits of the input integer will be lost.";
453
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000454 // Lazily create the BugType object. This will be owned
455 // by the BugReporter object 'BR' once we call BR.EmitWarning.
456 if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
457 RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
458 report->addRange(Ex->getSourceRange());
459 BR.EmitReport(report);
Ted Kremenekc1290552008-06-26 23:59:48 +0000460}
461
462GRSimpleAPICheck*
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000463clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
464 return new AuditCFNumberCreate(Ctx, BR);
Ted Kremenekc1290552008-06-26 23:59:48 +0000465}
466
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000467//===----------------------------------------------------------------------===//
468// Check registration.
469
470void clang::RegisterAppleChecks(GRExprEngine& Eng) {
471 ASTContext& Ctx = Eng.getContext();
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000472 BugReporter &BR = Eng.getBugReporter();
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000473
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000474 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR),
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000475 Stmt::ObjCMessageExprClass);
476
Ted Kremenekc0cccca2009-06-18 23:58:37 +0000477 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR),
Ted Kremenekb3538ab2008-09-18 21:25:13 +0000478 Stmt::CallExprClass);
479
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000480 RegisterNSErrorChecks(BR, Eng);
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000481}