blob: e170aa56c5cbb401a26019071b2a7bbfb677ec3e [file] [log] [blame]
Ted Kremenek99c6ad32008-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
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +000016#include "ClangSACheckers.h"
Ted Kremenek928c4152011-03-17 04:01:35 +000017#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000018#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000019#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Jordan Rosef540c542012-07-26 21:39:41 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
Argyrios Kyrtzidis983326f2011-02-23 01:05:36 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000022#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000023#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Ted Kremenek18c66fd2011-08-15 22:09:50 +000024#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000025#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Daniel Dunbarc4a1dea2008-08-11 05:35:13 +000027#include "clang/AST/DeclObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000028#include "clang/AST/Expr.h"
Steve Narofff494b572008-05-29 21:12:08 +000029#include "clang/AST/ExprObjC.h"
Jordan Rose1895a0a2012-06-11 16:40:41 +000030#include "clang/AST/StmtObjC.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000031#include "clang/AST/ASTContext.h"
Benjamin Kramer8fe83e12012-02-04 13:45:25 +000032#include "llvm/ADT/SmallString.h"
Jordan Rose9765ea92012-06-11 16:40:37 +000033#include "llvm/ADT/StringMap.h"
Ted Kremenek99c6ad32008-03-27 07:25:52 +000034
Ted Kremenek99c6ad32008-03-27 07:25:52 +000035using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000036using namespace ento;
Ted Kremenek52755612008-03-27 17:17:22 +000037
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000038namespace {
39class APIMisuse : public BugType {
40public:
41 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
42};
43} // end anonymous namespace
44
45//===----------------------------------------------------------------------===//
46// Utility functions.
47//===----------------------------------------------------------------------===//
48
Jordan Rosede507ea2012-07-02 19:28:04 +000049static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
Anders Carlssonb62bdce2011-03-08 20:05:26 +000050 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
Jordan Rosede507ea2012-07-02 19:28:04 +000051 return ID->getIdentifier()->getName();
52 return StringRef();
Ted Kremenek4ba62832008-03-27 22:05:32 +000053}
Ted Kremenek52755612008-03-27 17:17:22 +000054
Jordan Rose9765ea92012-06-11 16:40:37 +000055enum FoundationClass {
56 FC_None,
57 FC_NSArray,
58 FC_NSDictionary,
59 FC_NSEnumerator,
60 FC_NSOrderedSet,
61 FC_NSSet,
62 FC_NSString
63};
Anders Carlssonb62bdce2011-03-08 20:05:26 +000064
Jordan Rose9765ea92012-06-11 16:40:37 +000065static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
66 static llvm::StringMap<FoundationClass> Classes;
67 if (Classes.empty()) {
68 Classes["NSArray"] = FC_NSArray;
69 Classes["NSDictionary"] = FC_NSDictionary;
70 Classes["NSEnumerator"] = FC_NSEnumerator;
71 Classes["NSOrderedSet"] = FC_NSOrderedSet;
72 Classes["NSSet"] = FC_NSSet;
73 Classes["NSString"] = FC_NSString;
74 }
Anders Carlssonb62bdce2011-03-08 20:05:26 +000075
Jordan Rose9765ea92012-06-11 16:40:37 +000076 // FIXME: Should we cache this at all?
77 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
78 if (result == FC_None)
79 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
80 return findKnownClass(Super);
81
82 return result;
Ted Kremenek99c6ad32008-03-27 07:25:52 +000083}
84
Zhongxing Xu1c96b242008-10-17 05:57:07 +000085static inline bool isNil(SVal X) {
Mike Stump1eb44332009-09-09 15:08:12 +000086 return isa<loc::ConcreteInt>(X);
Ted Kremeneke5d5c202008-03-27 21:15:17 +000087}
88
Ted Kremenek99c6ad32008-03-27 07:25:52 +000089//===----------------------------------------------------------------------===//
Ted Kremenek2ce2baa2010-10-20 23:38:56 +000090// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
Ted Kremenek99c6ad32008-03-27 07:25:52 +000091//===----------------------------------------------------------------------===//
92
Benjamin Kramercb9c0742010-10-22 16:33:16 +000093namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000094 class NilArgChecker : public Checker<check::PreObjCMessage> {
Dylan Noblesmith6f42b622012-02-05 02:12:40 +000095 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000096
97 void WarnNilArg(CheckerContext &C,
Jordan Rosede507ea2012-07-02 19:28:04 +000098 const ObjCMethodCall &msg, unsigned Arg) const;
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +000099
Benjamin Kramercb9c0742010-10-22 16:33:16 +0000100 public:
Jordan Rosede507ea2012-07-02 19:28:04 +0000101 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
Benjamin Kramercb9c0742010-10-22 16:33:16 +0000102 };
103}
Mike Stump1eb44332009-09-09 15:08:12 +0000104
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000105void NilArgChecker::WarnNilArg(CheckerContext &C,
Jordan Rosede507ea2012-07-02 19:28:04 +0000106 const ObjCMethodCall &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000107 unsigned int Arg) const
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000108{
109 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000110 BT.reset(new APIMisuse("nil argument"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000111
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000112 if (ExplodedNode *N = C.generateSink()) {
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000113 SmallString<128> sbuf;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000114 llvm::raw_svector_ostream os(sbuf);
Jordan Rosede507ea2012-07-02 19:28:04 +0000115 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000116 << msg.getSelector().getAsString() << "' cannot be nil";
Mike Stump1eb44332009-09-09 15:08:12 +0000117
Anna Zakse172e8b2011-08-17 23:00:25 +0000118 BugReport *R = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000119 R->addRange(msg.getArgSourceRange(Arg));
Jordan Rose785950e2012-11-02 01:53:40 +0000120 C.emitReport(R);
Ted Kremenek4ba62832008-03-27 22:05:32 +0000121 }
Ted Kremenek4ba62832008-03-27 22:05:32 +0000122}
123
Jordan Rosede507ea2012-07-02 19:28:04 +0000124void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000125 CheckerContext &C) const {
Anders Carlssonb62bdce2011-03-08 20:05:26 +0000126 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
127 if (!ID)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000128 return;
129
Jordan Rose9765ea92012-06-11 16:40:37 +0000130 if (findKnownClass(ID) == FC_NSString) {
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000131 Selector S = msg.getSelector();
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000132
133 if (S.isUnarySelector())
134 return;
135
136 // FIXME: This is going to be really slow doing these checks with
137 // lexical comparisons.
138
139 std::string NameStr = S.getAsString();
Chris Lattner5f9e2722011-07-23 10:55:15 +0000140 StringRef Name(NameStr);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000141 assert(!Name.empty());
142
143 // FIXME: Checking for initWithFormat: will not work in most cases
144 // yet because [NSString alloc] returns id, not NSString*. We will
145 // need support for tracking expected-type information in the analyzer
146 // to find these errors.
147 if (Name == "caseInsensitiveCompare:" ||
148 Name == "compare:" ||
149 Name == "compare:options:" ||
150 Name == "compare:options:range:" ||
151 Name == "compare:options:range:locale:" ||
152 Name == "componentsSeparatedByCharactersInSet:" ||
153 Name == "initWithFormat:") {
Jordan Rosede507ea2012-07-02 19:28:04 +0000154 if (isNil(msg.getArgSVal(0)))
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000155 WarnNilArg(C, msg, 0);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000156 }
157 }
Ted Kremenek99c6ad32008-03-27 07:25:52 +0000158}
Ted Kremenek04bc8762008-06-26 23:59:48 +0000159
160//===----------------------------------------------------------------------===//
161// Error reporting.
162//===----------------------------------------------------------------------===//
163
164namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000165class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmith6f42b622012-02-05 02:12:40 +0000166 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000167 mutable IdentifierInfo* II;
Ted Kremenek04bc8762008-06-26 23:59:48 +0000168public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000169 CFNumberCreateChecker() : II(0) {}
170
171 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
172
Ted Kremenek04bc8762008-06-26 23:59:48 +0000173private:
Ted Kremenek9c378f72011-08-12 23:37:29 +0000174 void EmitError(const TypedRegion* R, const Expr *Ex,
Mike Stump1eb44332009-09-09 15:08:12 +0000175 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000176};
177} // end anonymous namespace
178
179enum CFNumberType {
180 kCFNumberSInt8Type = 1,
181 kCFNumberSInt16Type = 2,
182 kCFNumberSInt32Type = 3,
183 kCFNumberSInt64Type = 4,
184 kCFNumberFloat32Type = 5,
185 kCFNumberFloat64Type = 6,
186 kCFNumberCharType = 7,
187 kCFNumberShortType = 8,
188 kCFNumberIntType = 9,
189 kCFNumberLongType = 10,
190 kCFNumberLongLongType = 11,
191 kCFNumberFloatType = 12,
192 kCFNumberDoubleType = 13,
193 kCFNumberCFIndexType = 14,
194 kCFNumberNSIntegerType = 15,
195 kCFNumberCGFloatType = 16
196};
197
198namespace {
199 template<typename T>
200 class Optional {
201 bool IsKnown;
202 T Val;
203 public:
204 Optional() : IsKnown(false), Val(0) {}
205 Optional(const T& val) : IsKnown(true), Val(val) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000206
Ted Kremenek04bc8762008-06-26 23:59:48 +0000207 bool isKnown() const { return IsKnown; }
208
209 const T& getValue() const {
210 assert (isKnown());
211 return Val;
212 }
213
214 operator const T&() const {
215 return getValue();
216 }
217 };
218}
219
Ted Kremenek9c378f72011-08-12 23:37:29 +0000220static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
Nuno Lopes2550d702009-12-23 17:49:57 +0000221 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
Mike Stump1eb44332009-09-09 15:08:12 +0000222
Ted Kremenek04bc8762008-06-26 23:59:48 +0000223 if (i < kCFNumberCharType)
224 return FixedSize[i-1];
Mike Stump1eb44332009-09-09 15:08:12 +0000225
Ted Kremenek04bc8762008-06-26 23:59:48 +0000226 QualType T;
Mike Stump1eb44332009-09-09 15:08:12 +0000227
Ted Kremenek04bc8762008-06-26 23:59:48 +0000228 switch (i) {
229 case kCFNumberCharType: T = Ctx.CharTy; break;
230 case kCFNumberShortType: T = Ctx.ShortTy; break;
231 case kCFNumberIntType: T = Ctx.IntTy; break;
232 case kCFNumberLongType: T = Ctx.LongTy; break;
233 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
234 case kCFNumberFloatType: T = Ctx.FloatTy; break;
235 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
236 case kCFNumberCFIndexType:
237 case kCFNumberNSIntegerType:
238 case kCFNumberCGFloatType:
Mike Stump1eb44332009-09-09 15:08:12 +0000239 // FIXME: We need a way to map from names to Type*.
Ted Kremenek04bc8762008-06-26 23:59:48 +0000240 default:
241 return Optional<uint64_t>();
242 }
Mike Stump1eb44332009-09-09 15:08:12 +0000243
Ted Kremenek04bc8762008-06-26 23:59:48 +0000244 return Ctx.getTypeSize(T);
245}
246
247#if 0
248static const char* GetCFNumberTypeStr(uint64_t i) {
249 static const char* Names[] = {
250 "kCFNumberSInt8Type",
251 "kCFNumberSInt16Type",
252 "kCFNumberSInt32Type",
253 "kCFNumberSInt64Type",
254 "kCFNumberFloat32Type",
255 "kCFNumberFloat64Type",
256 "kCFNumberCharType",
257 "kCFNumberShortType",
258 "kCFNumberIntType",
259 "kCFNumberLongType",
260 "kCFNumberLongLongType",
261 "kCFNumberFloatType",
262 "kCFNumberDoubleType",
263 "kCFNumberCFIndexType",
264 "kCFNumberNSIntegerType",
265 "kCFNumberCGFloatType"
266 };
Mike Stump1eb44332009-09-09 15:08:12 +0000267
Ted Kremenek04bc8762008-06-26 23:59:48 +0000268 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
269}
270#endif
271
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000272void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
273 CheckerContext &C) const {
Ted Kremenek8bef8232012-01-26 21:29:00 +0000274 ProgramStateRef state = C.getState();
Anna Zaksb805c8f2011-12-01 05:57:37 +0000275 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000276 if (!FD)
277 return;
278
279 ASTContext &Ctx = C.getASTContext();
280 if (!II)
281 II = &Ctx.Idents.get("CFNumberCreate");
282
283 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
284 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000285
Ted Kremenek04bc8762008-06-26 23:59:48 +0000286 // Get the value of the "theType" argument.
Ted Kremenek5eca4822012-01-06 22:09:28 +0000287 const LocationContext *LCtx = C.getLocationContext();
288 SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
Mike Stump1eb44332009-09-09 15:08:12 +0000289
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000290 // FIXME: We really should allow ranges of valid theType values, and
291 // bifurcate the state appropriately.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000292 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000293 if (!V)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000294 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000295
Ted Kremenek04bc8762008-06-26 23:59:48 +0000296 uint64_t NumberKind = V->getValue().getLimitedValue();
297 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
Mike Stump1eb44332009-09-09 15:08:12 +0000298
Ted Kremenek04bc8762008-06-26 23:59:48 +0000299 // FIXME: In some cases we can emit an error.
300 if (!TargetSize.isKnown())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000301 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000302
Ted Kremenek04bc8762008-06-26 23:59:48 +0000303 // Look at the value of the integer being passed by reference. Essentially
304 // we want to catch cases where the value passed in is not equal to the
305 // size of the type being created.
Ted Kremenek5eca4822012-01-06 22:09:28 +0000306 SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Ted Kremenek04bc8762008-06-26 23:59:48 +0000308 // FIXME: Eventually we should handle arbitrary locations. We can do this
309 // by having an enhanced memory model that does low-level typing.
Zhongxing Xu1c96b242008-10-17 05:57:07 +0000310 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
Ted Kremenek04bc8762008-06-26 23:59:48 +0000311 if (!LV)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000312 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000313
Ted Kremenek96979342011-08-12 20:02:48 +0000314 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000315 if (!R)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000316 return;
Ted Kremenek5e77eba2009-07-29 18:17:40 +0000317
Zhongxing Xu018220c2010-08-11 06:10:55 +0000318 QualType T = Ctx.getCanonicalType(R->getValueType());
Mike Stump1eb44332009-09-09 15:08:12 +0000319
Ted Kremenek04bc8762008-06-26 23:59:48 +0000320 // FIXME: If the pointee isn't an integer type, should we flag a warning?
321 // People can do weird stuff with pointers.
Mike Stump1eb44332009-09-09 15:08:12 +0000322
323 if (!T->isIntegerType())
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000324 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000325
Ted Kremenek04bc8762008-06-26 23:59:48 +0000326 uint64_t SourceSize = Ctx.getTypeSize(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000327
Ted Kremenek04bc8762008-06-26 23:59:48 +0000328 // CHECK: is SourceSize == TargetSize
Ted Kremenek04bc8762008-06-26 23:59:48 +0000329 if (SourceSize == TargetSize)
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000330 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000331
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000332 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
333 // otherwise generate a regular node.
334 //
Ted Kremenek04bc8762008-06-26 23:59:48 +0000335 // FIXME: We can actually create an abstract "CFNumber" object that has
336 // the bits initialized to the provided values.
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000337 //
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000338 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
Anna Zaks0bd6b112011-10-26 21:06:34 +0000339 : C.addTransition()) {
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000340 SmallString<128> sbuf;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000341 llvm::raw_svector_ostream os(sbuf);
342
343 os << (SourceSize == 8 ? "An " : "A ")
344 << SourceSize << " bit integer is used to initialize a CFNumber "
345 "object that represents "
346 << (TargetSize == 8 ? "an " : "a ")
347 << TargetSize << " bit integer. ";
348
349 if (SourceSize < TargetSize)
350 os << (TargetSize - SourceSize)
351 << " bits of the CFNumber value will be garbage." ;
352 else
353 os << (SourceSize - TargetSize)
354 << " bits of the input integer will be lost.";
Ted Kremenek04bc8762008-06-26 23:59:48 +0000355
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000356 if (!BT)
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000357 BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000358
Anna Zakse172e8b2011-08-17 23:00:25 +0000359 BugReport *report = new BugReport(*BT, os.str(), N);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000360 report->addRange(CE->getArg(2)->getSourceRange());
Jordan Rose785950e2012-11-02 01:53:40 +0000361 C.emitReport(report);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000362 }
Ted Kremenek04bc8762008-06-26 23:59:48 +0000363}
364
Ted Kremenek78d46242008-07-22 16:21:24 +0000365//===----------------------------------------------------------------------===//
Jordy Rose61fb55c2010-07-06 02:34:42 +0000366// CFRetain/CFRelease checking for null arguments.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000367//===----------------------------------------------------------------------===//
368
369namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000370class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
Dylan Noblesmith6f42b622012-02-05 02:12:40 +0000371 mutable OwningPtr<APIMisuse> BT;
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000372 mutable IdentifierInfo *Retain, *Release;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000373public:
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000374 CFRetainReleaseChecker(): Retain(0), Release(0) {}
Ted Kremenek9c378f72011-08-12 23:37:29 +0000375 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000376};
377} // end anonymous namespace
378
379
Ted Kremenek9c378f72011-08-12 23:37:29 +0000380void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
381 CheckerContext &C) const {
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000382 // If the CallExpr doesn't have exactly 1 argument just give up checking.
383 if (CE->getNumArgs() != 1)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000384 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000385
Ted Kremenek8bef8232012-01-26 21:29:00 +0000386 ProgramStateRef state = C.getState();
Anna Zaksb805c8f2011-12-01 05:57:37 +0000387 const FunctionDecl *FD = C.getCalleeDecl(CE);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000388 if (!FD)
Jordy Rose61fb55c2010-07-06 02:34:42 +0000389 return;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000390
391 if (!BT) {
392 ASTContext &Ctx = C.getASTContext();
393 Retain = &Ctx.Idents.get("CFRetain");
394 Release = &Ctx.Idents.get("CFRelease");
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000395 BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000396 }
Mike Stump1eb44332009-09-09 15:08:12 +0000397
Jordy Rose61fb55c2010-07-06 02:34:42 +0000398 // Check if we called CFRetain/CFRelease.
Mike Stump1eb44332009-09-09 15:08:12 +0000399 const IdentifierInfo *FuncII = FD->getIdentifier();
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000400 if (!(FuncII == Retain || FuncII == Release))
Jordy Rose61fb55c2010-07-06 02:34:42 +0000401 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000402
Jordy Rose61fb55c2010-07-06 02:34:42 +0000403 // FIXME: The rest of this just checks that the argument is non-null.
404 // It should probably be refactored and combined with AttrNonNullChecker.
405
406 // Get the argument's value.
407 const Expr *Arg = CE->getArg(0);
Ted Kremenek5eca4822012-01-06 22:09:28 +0000408 SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
Jordy Rose61fb55c2010-07-06 02:34:42 +0000409 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
410 if (!DefArgVal)
411 return;
412
413 // Get a NULL value.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000414 SValBuilder &svalBuilder = C.getSValBuilder();
415 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
Jordy Rose61fb55c2010-07-06 02:34:42 +0000416
417 // Make an expression asserting that they're equal.
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000418 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000419
420 // Are they equal?
Ted Kremenek8bef8232012-01-26 21:29:00 +0000421 ProgramStateRef stateTrue, stateFalse;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000422 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000423
424 if (stateTrue && !stateFalse) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000425 ExplodedNode *N = C.generateSink(stateTrue);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000426 if (!N)
427 return;
428
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000429 const char *description = (FuncII == Retain)
430 ? "Null pointer argument in call to CFRetain"
431 : "Null pointer argument in call to CFRelease";
432
Anna Zakse172e8b2011-08-17 23:00:25 +0000433 BugReport *report = new BugReport(*BT, description, N);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000434 report->addRange(Arg->getSourceRange());
Jordan Rosea1f81bb2012-08-28 00:50:51 +0000435 bugreporter::trackNullOrUndefValue(N, Arg, *report);
Jordan Rose785950e2012-11-02 01:53:40 +0000436 C.emitReport(report);
Jordy Rose61fb55c2010-07-06 02:34:42 +0000437 return;
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000438 }
439
Jordy Rose61fb55c2010-07-06 02:34:42 +0000440 // From here on, we know the argument is non-null.
Anna Zaks0bd6b112011-10-26 21:06:34 +0000441 C.addTransition(stateFalse);
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000442}
443
444//===----------------------------------------------------------------------===//
Ted Kremenek50e837b2009-11-20 05:27:05 +0000445// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
446//===----------------------------------------------------------------------===//
447
448namespace {
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +0000449class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000450 mutable Selector releaseS;
451 mutable Selector retainS;
452 mutable Selector autoreleaseS;
453 mutable Selector drainS;
Dylan Noblesmith6f42b622012-02-05 02:12:40 +0000454 mutable OwningPtr<BugType> BT;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000455
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000456public:
Jordan Rosede507ea2012-07-02 19:28:04 +0000457 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Ted Kremenek50e837b2009-11-20 05:27:05 +0000458};
459}
460
Jordan Rosede507ea2012-07-02 19:28:04 +0000461void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000462 CheckerContext &C) const {
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000463
464 if (!BT) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000465 BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
466 "instance"));
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000467
468 ASTContext &Ctx = C.getASTContext();
469 releaseS = GetNullarySelector("release", Ctx);
470 retainS = GetNullarySelector("retain", Ctx);
471 autoreleaseS = GetNullarySelector("autorelease", Ctx);
472 drainS = GetNullarySelector("drain", Ctx);
473 }
474
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000475 if (msg.isInstanceMessage())
Ted Kremenek50e837b2009-11-20 05:27:05 +0000476 return;
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000477 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
478 assert(Class);
Douglas Gregor04badcf2010-04-21 00:45:42 +0000479
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000480 Selector S = msg.getSelector();
Benjamin Kramer921ddc42009-11-20 10:03:00 +0000481 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
Ted Kremenek50e837b2009-11-20 05:27:05 +0000482 return;
483
Anna Zaks0bd6b112011-10-26 21:06:34 +0000484 if (ExplodedNode *N = C.addTransition()) {
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000485 SmallString<200> buf;
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000486 llvm::raw_svector_ostream os(buf);
Ted Kremenek19d67b52009-11-23 22:22:01 +0000487
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000488 os << "The '" << S.getAsString() << "' message should be sent to instances "
489 "of class '" << Class->getName()
490 << "' and not the class directly";
Ted Kremenek50e837b2009-11-20 05:27:05 +0000491
Anna Zakse172e8b2011-08-17 23:00:25 +0000492 BugReport *report = new BugReport(*BT, os.str(), N);
Argyrios Kyrtzidis432424d2011-01-25 00:03:53 +0000493 report->addRange(msg.getSourceRange());
Jordan Rose785950e2012-11-02 01:53:40 +0000494 C.emitReport(report);
Ted Kremenek2ce2baa2010-10-20 23:38:56 +0000495 }
Ted Kremenek50e837b2009-11-20 05:27:05 +0000496}
497
498//===----------------------------------------------------------------------===//
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000499// Check for passing non-Objective-C types to variadic methods that expect
500// only Objective-C types.
501//===----------------------------------------------------------------------===//
502
503namespace {
504class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
505 mutable Selector arrayWithObjectsS;
506 mutable Selector dictionaryWithObjectsAndKeysS;
507 mutable Selector setWithObjectsS;
Jordy Rosef439e002012-04-06 19:06:01 +0000508 mutable Selector orderedSetWithObjectsS;
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000509 mutable Selector initWithObjectsS;
510 mutable Selector initWithObjectsAndKeysS;
Dylan Noblesmith6f42b622012-02-05 02:12:40 +0000511 mutable OwningPtr<BugType> BT;
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000512
Jordan Rosede507ea2012-07-02 19:28:04 +0000513 bool isVariadicMessage(const ObjCMethodCall &msg) const;
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000514
515public:
Jordan Rosede507ea2012-07-02 19:28:04 +0000516 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000517};
518}
519
520/// isVariadicMessage - Returns whether the given message is a variadic message,
521/// where all arguments must be Objective-C types.
522bool
Jordan Rosede507ea2012-07-02 19:28:04 +0000523VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
524 const ObjCMethodDecl *MD = msg.getDecl();
Ted Kremenek9281efe2011-04-12 21:47:05 +0000525
526 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000527 return false;
528
529 Selector S = msg.getSelector();
530
531 if (msg.isInstanceMessage()) {
532 // FIXME: Ideally we'd look at the receiver interface here, but that's not
533 // useful for init, because alloc returns 'id'. In theory, this could lead
534 // to false positives, for example if there existed a class that had an
535 // initWithObjects: implementation that does accept non-Objective-C pointer
536 // types, but the chance of that happening is pretty small compared to the
537 // gains that this analysis gives.
538 const ObjCInterfaceDecl *Class = MD->getClassInterface();
539
Jordan Rose9765ea92012-06-11 16:40:37 +0000540 switch (findKnownClass(Class)) {
541 case FC_NSArray:
542 case FC_NSOrderedSet:
543 case FC_NSSet:
544 return S == initWithObjectsS;
545 case FC_NSDictionary:
546 return S == initWithObjectsAndKeysS;
547 default:
548 return false;
549 }
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000550 } else {
551 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
552
Jordan Rose9765ea92012-06-11 16:40:37 +0000553 switch (findKnownClass(Class)) {
554 case FC_NSArray:
555 return S == arrayWithObjectsS;
556 case FC_NSOrderedSet:
557 return S == orderedSetWithObjectsS;
558 case FC_NSSet:
559 return S == setWithObjectsS;
560 case FC_NSDictionary:
561 return S == dictionaryWithObjectsAndKeysS;
562 default:
563 return false;
564 }
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000565 }
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000566}
567
Jordan Rosede507ea2012-07-02 19:28:04 +0000568void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000569 CheckerContext &C) const {
570 if (!BT) {
571 BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
572 "Objective-C pointer types"));
573
574 ASTContext &Ctx = C.getASTContext();
575 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
576 dictionaryWithObjectsAndKeysS =
577 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
578 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
Jordy Rosef439e002012-04-06 19:06:01 +0000579 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000580
581 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
582 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
583 }
584
585 if (!isVariadicMessage(msg))
586 return;
587
588 // We are not interested in the selector arguments since they have
589 // well-defined types, so the compiler will issue a warning for them.
590 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
591
592 // We're not interested in the last argument since it has to be nil or the
593 // compiler would have issued a warning for it elsewhere.
594 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
595
596 if (variadicArgsEnd <= variadicArgsBegin)
597 return;
598
599 // Verify that all arguments have Objective-C types.
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000600 llvm::Optional<ExplodedNode*> errorNode;
Ted Kremenek8bef8232012-01-26 21:29:00 +0000601 ProgramStateRef state = C.getState();
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000602
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000603 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
Jordan Rosede507ea2012-07-02 19:28:04 +0000604 QualType ArgTy = msg.getArgExpr(I)->getType();
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000605 if (ArgTy->isObjCObjectPointerType())
606 continue;
607
Anders Carlssonf05982b2011-04-19 01:16:46 +0000608 // Block pointers are treaded as Objective-C pointers.
609 if (ArgTy->isBlockPointerType())
610 continue;
611
Ted Kremenekd5fde212011-03-16 00:22:51 +0000612 // Ignore pointer constants.
Jordan Rosede507ea2012-07-02 19:28:04 +0000613 if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
Ted Kremenekd5fde212011-03-16 00:22:51 +0000614 continue;
Ted Kremenek928c4152011-03-17 04:01:35 +0000615
Ted Kremenekf3f92932011-03-17 04:10:25 +0000616 // Ignore pointer types annotated with 'NSObject' attribute.
617 if (C.getASTContext().isObjCNSObjectType(ArgTy))
618 continue;
619
Ted Kremenek928c4152011-03-17 04:01:35 +0000620 // Ignore CF references, which can be toll-free bridged.
Ted Kremenek05560482011-07-16 19:50:32 +0000621 if (coreFoundation::isCFObjectRef(ArgTy))
Ted Kremenek928c4152011-03-17 04:01:35 +0000622 continue;
Ted Kremenekd5fde212011-03-16 00:22:51 +0000623
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000624 // Generate only one error node to use for all bug reports.
Jordan Rosede507ea2012-07-02 19:28:04 +0000625 if (!errorNode.hasValue())
Anna Zaks0bd6b112011-10-26 21:06:34 +0000626 errorNode = C.addTransition();
Ted Kremenek6fb5c1f2011-03-14 19:50:37 +0000627
628 if (!errorNode.getValue())
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000629 continue;
630
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000631 SmallString<128> sbuf;
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000632 llvm::raw_svector_ostream os(sbuf);
633
Jordan Rosede507ea2012-07-02 19:28:04 +0000634 StringRef TypeName = GetReceiverInterfaceName(msg);
635 if (!TypeName.empty())
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000636 os << "Argument to '" << TypeName << "' method '";
637 else
638 os << "Argument to method '";
639
640 os << msg.getSelector().getAsString()
Jordan Rosede507ea2012-07-02 19:28:04 +0000641 << "' should be an Objective-C pointer type, not '";
642 ArgTy.print(os, C.getLangOpts());
643 os << "'";
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000644
Jordan Rosede507ea2012-07-02 19:28:04 +0000645 BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000646 R->addRange(msg.getArgSourceRange(I));
Jordan Rose785950e2012-11-02 01:53:40 +0000647 C.emitReport(R);
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000648 }
649}
650
651//===----------------------------------------------------------------------===//
Jordan Rose1895a0a2012-06-11 16:40:41 +0000652// Improves the modeling of loops over Cocoa collections.
653//===----------------------------------------------------------------------===//
654
655namespace {
656class ObjCLoopChecker
657 : public Checker<check::PostStmt<ObjCForCollectionStmt> > {
658
659public:
660 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
661};
662}
663
664static bool isKnownNonNilCollectionType(QualType T) {
665 const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
666 if (!PT)
667 return false;
668
669 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
670 if (!ID)
671 return false;
672
673 switch (findKnownClass(ID)) {
674 case FC_NSArray:
675 case FC_NSDictionary:
676 case FC_NSEnumerator:
677 case FC_NSOrderedSet:
678 case FC_NSSet:
679 return true;
680 default:
681 return false;
682 }
683}
684
685void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
686 CheckerContext &C) const {
687 ProgramStateRef State = C.getState();
688
689 // Check if this is the branch for the end of the loop.
690 SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext());
691 if (CollectionSentinel.isZeroConstant())
692 return;
693
694 // See if the collection is one where we /know/ the elements are non-nil.
695 const Expr *Collection = FCS->getCollection();
696 if (!isKnownNonNilCollectionType(Collection->getType()))
697 return;
698
699 // FIXME: Copied from ExprEngineObjC.
700 const Stmt *Element = FCS->getElement();
701 SVal ElementVar;
702 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
703 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
704 assert(ElemDecl->getInit() == 0);
705 ElementVar = State->getLValue(ElemDecl, C.getLocationContext());
706 } else {
707 ElementVar = State->getSVal(Element, C.getLocationContext());
708 }
709
710 if (!isa<Loc>(ElementVar))
711 return;
712
713 // Go ahead and assume the value is non-nil.
714 SVal Val = State->getSVal(cast<Loc>(ElementVar));
715 State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
716 C.addTransition(State);
717}
718
Anna Zaks26663612012-08-22 21:19:56 +0000719namespace {
720/// \class ObjCNonNilReturnValueChecker
Anna Zaks05fcbd32012-08-30 19:40:52 +0000721/// \brief The checker restricts the return values of APIs known to
722/// never (or almost never) return 'nil'.
Anna Zaks26663612012-08-22 21:19:56 +0000723class ObjCNonNilReturnValueChecker
724 : public Checker<check::PostObjCMessage> {
725 mutable bool Initialized;
726 mutable Selector ObjectAtIndex;
727 mutable Selector ObjectAtIndexedSubscript;
Anna Zaks769bc072012-08-22 22:47:58 +0000728
Anna Zaks26663612012-08-22 21:19:56 +0000729public:
Anna Zaks769bc072012-08-22 22:47:58 +0000730 ObjCNonNilReturnValueChecker() : Initialized(false) {}
Anna Zaks26663612012-08-22 21:19:56 +0000731 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
732};
733}
734
Benjamin Kramerda885362012-09-10 11:57:16 +0000735static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
736 ProgramStateRef State,
737 CheckerContext &C) {
Anna Zaks05fcbd32012-08-30 19:40:52 +0000738 SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
Anna Zaksdc601f42012-08-30 22:42:41 +0000739 if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
Anna Zaks43d39742012-08-30 22:55:32 +0000740 return State->assume(*DV, true);
Anna Zaksdc601f42012-08-30 22:42:41 +0000741 return State;
Anna Zaks05fcbd32012-08-30 19:40:52 +0000742}
743
Anna Zaks26663612012-08-22 21:19:56 +0000744void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
745 CheckerContext &C)
Anna Zaks05fcbd32012-08-30 19:40:52 +0000746 const {
Anna Zaks26663612012-08-22 21:19:56 +0000747 ProgramStateRef State = C.getState();
748
749 if (!Initialized) {
750 ASTContext &Ctx = C.getASTContext();
751 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
752 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
753 }
754
755 // Check the receiver type.
756 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
Anna Zaks05fcbd32012-08-30 19:40:52 +0000757
758 // Assume that object returned from '[self init]' or '[super init]' is not
759 // 'nil' if we are processing an inlined function/method.
760 //
761 // A defensive callee will (and should) check if the object returned by
762 // '[super init]' is 'nil' before doing it's own initialization. However,
763 // since 'nil' is rarely returned in practice, we should not warn when the
764 // caller to the defensive constructor uses the object in contexts where
765 // 'nil' is not accepted.
Anna Zaksc6933392012-09-25 00:31:43 +0000766 if (C.isWithinInlined() && M.getDecl() &&
Anna Zaks05fcbd32012-08-30 19:40:52 +0000767 M.getDecl()->getMethodFamily() == OMF_init &&
768 M.isReceiverSelfOrSuper()) {
769 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
770 }
771
772 // Objects returned from
773 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
774 // are never 'nil'.
Anna Zaks26663612012-08-22 21:19:56 +0000775 FoundationClass Cl = findKnownClass(Interface);
776 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
777 Selector Sel = M.getSelector();
778 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
779 // Go ahead and assume the value is non-nil.
Anna Zaks05fcbd32012-08-30 19:40:52 +0000780 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
Anna Zaks26663612012-08-22 21:19:56 +0000781 }
782 }
783 }
Anna Zaks05fcbd32012-08-30 19:40:52 +0000784 C.addTransition(State);
Anna Zaks26663612012-08-22 21:19:56 +0000785}
Jordan Rose1895a0a2012-06-11 16:40:41 +0000786
787//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000788// Check registration.
Ted Kremenek79b4f7d2009-07-14 00:43:42 +0000789//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000790
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000791void ento::registerNilArgChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000792 mgr.registerChecker<NilArgChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000793}
794
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000795void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000796 mgr.registerChecker<CFNumberCreateChecker>();
Argyrios Kyrtzidis0b1ba622011-02-16 01:40:52 +0000797}
798
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000799void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000800 mgr.registerChecker<CFRetainReleaseChecker>();
Ted Kremenek78d46242008-07-22 16:21:24 +0000801}
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000802
803void ento::registerClassReleaseChecker(CheckerManager &mgr) {
Argyrios Kyrtzidis74eed0e2011-02-23 00:16:10 +0000804 mgr.registerChecker<ClassReleaseChecker>();
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000805}
Anders Carlsson4597b7b2011-03-13 20:35:21 +0000806
807void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
808 mgr.registerChecker<VariadicMethodTypeChecker>();
809}
Jordan Rose1895a0a2012-06-11 16:40:41 +0000810
811void ento::registerObjCLoopChecker(CheckerManager &mgr) {
812 mgr.registerChecker<ObjCLoopChecker>();
813}
Anna Zaks26663612012-08-22 21:19:56 +0000814
815void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
816 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
817}