blob: 0eee9374da362121724532885f80ba36e16ae908 [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 Kremenekabd89ac2008-08-13 04:27:00 +000069 GRStateManager* VMgr;
Ted Kremenekbf6babf2009-02-04 23:49:09 +000070
Zhongxing Xu097fc982008-10-17 05:57:07 +000071 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenekf00daf02008-04-03 17:57:38 +000072
73 bool isNSString(ObjCInterfaceType* T, const char* suffix);
74 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
75
76 void Warn(NodeTy* N, Expr* E, const std::string& s);
77 void WarnNilArg(NodeTy* N, Expr* E);
78
79 bool CheckNilArg(NodeTy* N, unsigned Arg);
80
81public:
Ted Kremenekbf6babf2009-02-04 23:49:09 +000082 BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr,
83 BugReporter& br)
84 : BT(0), BR(br), Ctx(ctx), VMgr(vmgr) {}
85
86 bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekf00daf02008-04-03 17:57:38 +000087
Ted Kremenekbf6babf2009-02-04 23:49:09 +000088private:
89 void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
90 std::string sbuf;
91 llvm::raw_string_ostream os(sbuf);
92 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
93 << ME->getSelector().getAsString() << "' cannot be nil.";
94
95 // Lazily create the BugType object for NilArg. This will be owned
96 // by the BugReporter object 'BR' once we call BR.EmitWarning.
97 if (!BT) BT = new APIMisuse("nil argument");
98
99 RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
100 R->addRange(ME->getArg(Arg)->getSourceRange());
101 BR.EmitReport(R);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000102 }
103};
104
105} // end anonymous namespace
106
107
108GRSimpleAPICheck*
109clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000110 GRStateManager* VMgr, BugReporter& BR) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000111
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000112 return new BasicObjCFoundationChecks(Ctx, VMgr, BR);
Ted Kremenekf00daf02008-04-03 17:57:38 +0000113}
114
115
116
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000117bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
118 GRStateManager&) {
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000119
120 ObjCMessageExpr* ME =
121 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000122
Ted Kremenek639247a2008-03-27 22:05:32 +0000123 ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000124
125 if (!ReceiverType)
Nuno Lopesf44f0932008-05-20 17:33:56 +0000126 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000127
Ted Kremenek639247a2008-03-27 22:05:32 +0000128 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
129
130 if (!name)
131 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000132
133 if (name[0] != 'N' || name[1] != 'S')
134 return false;
135
136 name += 2;
137
138 // FIXME: Make all of this faster.
139
140 if (isNSString(ReceiverType, name))
141 return AuditNSString(N, ME);
142
Nuno Lopesf44f0932008-05-20 17:33:56 +0000143 return false;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000144}
145
Zhongxing Xu097fc982008-10-17 05:57:07 +0000146static inline bool isNil(SVal X) {
147 return isa<loc::ConcreteInt>(X);
Ted Kremenek583c4382008-03-27 21:15:17 +0000148}
149
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000150//===----------------------------------------------------------------------===//
151// Error reporting.
152//===----------------------------------------------------------------------===//
153
Ted Kremenek639247a2008-03-27 22:05:32 +0000154bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
155 ObjCMessageExpr* ME =
156 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
157
158 Expr * E = ME->getArg(Arg);
159
Zhongxing Xu097fc982008-10-17 05:57:07 +0000160 if (isNil(GetSVal(N->getState(), E))) {
Ted Kremenekf00daf02008-04-03 17:57:38 +0000161 WarnNilArg(N, ME, Arg);
Ted Kremenek639247a2008-03-27 22:05:32 +0000162 return true;
163 }
164
165 return false;
166}
167
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000168//===----------------------------------------------------------------------===//
169// NSString checking.
170//===----------------------------------------------------------------------===//
171
172bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
173 const char* suffix) {
174
175 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
176}
177
178bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
179 ObjCMessageExpr* ME) {
180
181 Selector S = ME->getSelector();
182
183 if (S.isUnarySelector())
184 return false;
185
186 // FIXME: This is going to be really slow doing these checks with
187 // lexical comparisons.
188
Chris Lattner3a8f2942008-11-24 03:33:13 +0000189 std::string name = S.getAsString();
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000190 assert (!name.empty());
191 const char* cstr = &name[0];
192 unsigned len = name.size();
Ted Kremenek639247a2008-03-27 22:05:32 +0000193
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000194 switch (len) {
195 default:
196 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000197 case 8:
Ted Kremenek639247a2008-03-27 22:05:32 +0000198 if (!strcmp(cstr, "compare:"))
199 return CheckNilArg(N, 0);
200
201 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000202
203 case 15:
204 // FIXME: Checking for initWithFormat: will not work in most cases
205 // yet because [NSString alloc] returns id, not NSString*. We will
206 // need support for tracking expected-type information in the analyzer
207 // to find these errors.
208 if (!strcmp(cstr, "initWithFormat:"))
209 return CheckNilArg(N, 0);
210
211 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000212
Ted Kremenek639247a2008-03-27 22:05:32 +0000213 case 16:
214 if (!strcmp(cstr, "compare:options:"))
215 return CheckNilArg(N, 0);
Ted Kremenekb20dccc2008-03-27 21:23:57 +0000216
217 break;
Ted Kremenek639247a2008-03-27 22:05:32 +0000218
219 case 22:
220 if (!strcmp(cstr, "compare:options:range:"))
221 return CheckNilArg(N, 0);
222
223 break;
224
225 case 23:
226
227 if (!strcmp(cstr, "caseInsensitiveCompare:"))
228 return CheckNilArg(N, 0);
229
230 break;
Ted Kremenek44e74042008-03-28 16:09:38 +0000231
Ted Kremenek639247a2008-03-27 22:05:32 +0000232 case 29:
233 if (!strcmp(cstr, "compare:options:range:locale:"))
234 return CheckNilArg(N, 0);
235
236 break;
237
238 case 37:
239 if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
240 return CheckNilArg(N, 0);
241
242 break;
Ted Kremenekb0a2e472008-03-27 07:25:52 +0000243 }
244
245 return false;
246}
Ted Kremenekc1290552008-06-26 23:59:48 +0000247
248//===----------------------------------------------------------------------===//
249// Error reporting.
250//===----------------------------------------------------------------------===//
251
252namespace {
Ted Kremenekc1290552008-06-26 23:59:48 +0000253
Ted Kremenekc1290552008-06-26 23:59:48 +0000254class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000255 APIMisuse* BT;
Ted Kremenekc1290552008-06-26 23:59:48 +0000256
257 // FIXME: Either this should be refactored into GRSimpleAPICheck, or
258 // it should always be passed with a call to Audit. The latter
259 // approach makes this class more stateless.
260 ASTContext& Ctx;
261 IdentifierInfo* II;
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000262 GRStateManager* VMgr;
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000263 BugReporter& BR;
Ted Kremenekc1290552008-06-26 23:59:48 +0000264
Zhongxing Xu097fc982008-10-17 05:57:07 +0000265 SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
Ted Kremenekc1290552008-06-26 23:59:48 +0000266
267public:
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000268 AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr, BugReporter& br)
269 : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr), BR(br){}
Ted Kremenekc1290552008-06-26 23:59:48 +0000270
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000271 ~AuditCFNumberCreate() {}
Ted Kremenekc1290552008-06-26 23:59:48 +0000272
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000273 bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
Ted Kremenekc1290552008-06-26 23:59:48 +0000274
275private:
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000276 void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000277 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
278};
279} // end anonymous namespace
280
281enum CFNumberType {
282 kCFNumberSInt8Type = 1,
283 kCFNumberSInt16Type = 2,
284 kCFNumberSInt32Type = 3,
285 kCFNumberSInt64Type = 4,
286 kCFNumberFloat32Type = 5,
287 kCFNumberFloat64Type = 6,
288 kCFNumberCharType = 7,
289 kCFNumberShortType = 8,
290 kCFNumberIntType = 9,
291 kCFNumberLongType = 10,
292 kCFNumberLongLongType = 11,
293 kCFNumberFloatType = 12,
294 kCFNumberDoubleType = 13,
295 kCFNumberCFIndexType = 14,
296 kCFNumberNSIntegerType = 15,
297 kCFNumberCGFloatType = 16
298};
299
300namespace {
301 template<typename T>
302 class Optional {
303 bool IsKnown;
304 T Val;
305 public:
306 Optional() : IsKnown(false), Val(0) {}
307 Optional(const T& val) : IsKnown(true), Val(val) {}
308
309 bool isKnown() const { return IsKnown; }
310
311 const T& getValue() const {
312 assert (isKnown());
313 return Val;
314 }
315
316 operator const T&() const {
317 return getValue();
318 }
319 };
320}
321
322static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
323 static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
324
325 if (i < kCFNumberCharType)
326 return FixedSize[i-1];
327
328 QualType T;
329
330 switch (i) {
331 case kCFNumberCharType: T = Ctx.CharTy; break;
332 case kCFNumberShortType: T = Ctx.ShortTy; break;
333 case kCFNumberIntType: T = Ctx.IntTy; break;
334 case kCFNumberLongType: T = Ctx.LongTy; break;
335 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
336 case kCFNumberFloatType: T = Ctx.FloatTy; break;
337 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
338 case kCFNumberCFIndexType:
339 case kCFNumberNSIntegerType:
340 case kCFNumberCGFloatType:
341 // FIXME: We need a way to map from names to Type*.
342 default:
343 return Optional<uint64_t>();
344 }
345
346 return Ctx.getTypeSize(T);
347}
348
349#if 0
350static const char* GetCFNumberTypeStr(uint64_t i) {
351 static const char* Names[] = {
352 "kCFNumberSInt8Type",
353 "kCFNumberSInt16Type",
354 "kCFNumberSInt32Type",
355 "kCFNumberSInt64Type",
356 "kCFNumberFloat32Type",
357 "kCFNumberFloat64Type",
358 "kCFNumberCharType",
359 "kCFNumberShortType",
360 "kCFNumberIntType",
361 "kCFNumberLongType",
362 "kCFNumberLongLongType",
363 "kCFNumberFloatType",
364 "kCFNumberDoubleType",
365 "kCFNumberCFIndexType",
366 "kCFNumberNSIntegerType",
367 "kCFNumberCGFloatType"
368 };
369
370 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
371}
372#endif
373
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000374bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
Ted Kremenekc1290552008-06-26 23:59:48 +0000375 CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
376 Expr* Callee = CE->getCallee();
Zhongxing Xu097fc982008-10-17 05:57:07 +0000377 SVal CallV = GetSVal(N->getState(), Callee);
Zhongxing Xucac107a2009-04-20 05:24:46 +0000378 const FunctionDecl* FD = CallV.getAsFunctionDecl();
Ted Kremenekc1290552008-06-26 23:59:48 +0000379
Zhongxing Xucac107a2009-04-20 05:24:46 +0000380 if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
Ted Kremenekc1290552008-06-26 23:59:48 +0000381 return false;
382
383 // Get the value of the "theType" argument.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000384 SVal TheTypeVal = GetSVal(N->getState(), CE->getArg(1));
Ted Kremenekc1290552008-06-26 23:59:48 +0000385
386 // FIXME: We really should allow ranges of valid theType values, and
387 // bifurcate the state appropriately.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000388 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenekc1290552008-06-26 23:59:48 +0000389
390 if (!V)
391 return false;
392
393 uint64_t NumberKind = V->getValue().getLimitedValue();
394 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
395
396 // FIXME: In some cases we can emit an error.
397 if (!TargetSize.isKnown())
398 return false;
399
400 // Look at the value of the integer being passed by reference. Essentially
401 // we want to catch cases where the value passed in is not equal to the
402 // size of the type being created.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000403 SVal TheValueExpr = GetSVal(N->getState(), CE->getArg(2));
Ted Kremenekc1290552008-06-26 23:59:48 +0000404
405 // FIXME: Eventually we should handle arbitrary locations. We can do this
406 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu097fc982008-10-17 05:57:07 +0000407 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenekc1290552008-06-26 23:59:48 +0000408
409 if (!LV)
410 return false;
411
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000412 const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
Ted Kremenekf5da3252008-12-13 21:49:13 +0000413 if (!R) return false;
Ted Kremenekb15eba42008-10-04 05:50:14 +0000414
Ted Kremenek6a9b5352009-03-01 05:44:08 +0000415 while (const TypedViewRegion* ATR = dyn_cast<TypedViewRegion>(R)) {
Ted Kremenekf5da3252008-12-13 21:49:13 +0000416 R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
417 if (!R) return false;
418 }
Ted Kremenekb15eba42008-10-04 05:50:14 +0000419
Ted Kremenekf5da3252008-12-13 21:49:13 +0000420 QualType T = Ctx.getCanonicalType(R->getRValueType(Ctx));
Ted Kremenekc1290552008-06-26 23:59:48 +0000421
422 // FIXME: If the pointee isn't an integer type, should we flag a warning?
423 // People can do weird stuff with pointers.
424
425 if (!T->isIntegerType())
426 return false;
427
428 uint64_t SourceSize = Ctx.getTypeSize(T);
429
430 // CHECK: is SourceSize == TargetSize
431
432 if (SourceSize == TargetSize)
433 return false;
434
Ted Kremenekb15eba42008-10-04 05:50:14 +0000435 AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
Ted Kremenekc1290552008-06-26 23:59:48 +0000436
437 // FIXME: We can actually create an abstract "CFNumber" object that has
438 // the bits initialized to the provided values.
439 return SourceSize < TargetSize;
440}
441
Ted Kremenek38a4b4b2008-10-17 20:28:54 +0000442void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000443 ExplodedNode<GRState> *N,
Ted Kremenekc1290552008-06-26 23:59:48 +0000444 uint64_t SourceSize, uint64_t TargetSize,
445 uint64_t NumberKind) {
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000446
447 std::string sbuf;
448 llvm::raw_string_ostream os(sbuf);
Ted Kremenekc1290552008-06-26 23:59:48 +0000449
450 os << (SourceSize == 8 ? "An " : "A ")
451 << SourceSize << " bit integer is used to initialize a CFNumber "
452 "object that represents "
453 << (TargetSize == 8 ? "an " : "a ")
454 << TargetSize << " bit integer. ";
455
456 if (SourceSize < TargetSize)
457 os << (TargetSize - SourceSize)
458 << " bits of the CFNumber value will be garbage." ;
459 else
460 os << (SourceSize - TargetSize)
461 << " bits of the input integer will be lost.";
462
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000463 // Lazily create the BugType object. This will be owned
464 // by the BugReporter object 'BR' once we call BR.EmitWarning.
465 if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
466 RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
467 report->addRange(Ex->getSourceRange());
468 BR.EmitReport(report);
Ted Kremenekc1290552008-06-26 23:59:48 +0000469}
470
471GRSimpleAPICheck*
472clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000473 GRStateManager* VMgr, BugReporter& BR) {
474 return new AuditCFNumberCreate(Ctx, VMgr, BR);
Ted Kremenekc1290552008-06-26 23:59:48 +0000475}
476
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000477//===----------------------------------------------------------------------===//
478// Check registration.
479
480void clang::RegisterAppleChecks(GRExprEngine& Eng) {
481 ASTContext& Ctx = Eng.getContext();
Ted Kremenekabd89ac2008-08-13 04:27:00 +0000482 GRStateManager* VMgr = &Eng.getStateManager();
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000483 BugReporter &BR = Eng.getBugReporter();
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000484
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000485 Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr, BR),
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000486 Stmt::ObjCMessageExprClass);
487
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000488 Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr, BR),
Ted Kremenekb3538ab2008-09-18 21:25:13 +0000489 Stmt::CallExprClass);
490
Ted Kremenekbf6babf2009-02-04 23:49:09 +0000491 RegisterNSErrorChecks(BR, Eng);
Ted Kremenek9f20c7c2008-07-22 16:21:24 +0000492}