ObjCSelfInitChecker.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com//== ObjCSelfInitChecker.cpp - Checker for 'self' initialization -*- C++ -*--=// 2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// 3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// The LLVM Compiler Infrastructure 4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// 5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// This file is distributed under the University of Illinois Open Source 6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// License. See LICENSE.TXT for details. 7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// 8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com//===----------------------------------------------------------------------===// 9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// 108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// This defines ObjCSelfInitChecker, a builtin check that checks for uses of 118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 'self' before proper initialization. 128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com//===----------------------------------------------------------------------===// 148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// This checks initialization methods to verify that they assign 'self' to the 168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// result of an initialization call (e.g. [super init], or [self initWith..]) 178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// before using 'self' or any instance variable. 188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// To perform the required checking, values are tagged with flags that indicate 208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 1) if the object is the one pointed to by 'self', and 2) if the object 218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// is the result of an initializer (e.g. [super init]). 228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Uses of an object that is true for 1) but not 2) trigger a diagnostic. 248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// The uses that are currently checked are: 258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// - Using instance variables. 268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// - Returning the object. 278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Note that we don't check for an invalid 'self' that is the receiver of an 298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// obj-c message expression to cut down false positives where logging functions 308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// get information from self (like its class) or doing "invalidation" on self 318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// when the initialization fails. 328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Because the object that 'self' points to gets invalidated when a call 348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// receives a reference to 'self', the checker keeps track and passes the flags 358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// for 1) and 2) to the new object that 'self' points to after the call. 368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// 378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com//===----------------------------------------------------------------------===// 388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "ClangSACheckers.h" 408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/AST/ParentMap.h" 418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/Checker.h" 438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/CheckerManager.h" 448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "llvm/Support/raw_ostream.h" 488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comusing namespace clang; 508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comusing namespace ento; 518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); 538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isInitializationMethod(const ObjCMethodDecl *MD); 548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isInitMessage(const ObjCMethodCall &Msg); 558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isSelfVar(SVal location, CheckerContext &C); 568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace { 588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comclass ObjCSelfInitChecker : public Checker< check::PostObjCMessage, 598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::PostStmt<ObjCIvarRefExpr>, 608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::PreStmt<ReturnStmt>, 618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::PreCall, 628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::PostCall, 638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::Location, 648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com check::Bind > { 658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com mutable std::unique_ptr<BugType> BT; 668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkForInvalidSelf(const Expr *E, CheckerContext &C, 688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const char *errorStr) const; 698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.compublic: 718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ObjCSelfInitChecker() {} 728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const; 738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const; 748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkLocation(SVal location, bool isLoad, const Stmt *S, 768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const; 778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; 788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkPreCall(const CallEvent &CE, CheckerContext &C) const; 808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void checkPostCall(const CallEvent &CE, CheckerContext &C) const; 818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com void printState(raw_ostream &Out, ProgramStateRef State, 838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const char *NL, const char *Sep) const override; 848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}; 858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} // end anonymous namespace 868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace { 888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comenum SelfFlagEnum { 898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com /// \brief No flag set. 908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlag_None = 0x0, 918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com /// \brief Value came from 'self'. 928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlag_Self = 0x1, 938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com /// \brief Value came from the result of an initializer (e.g. [super init]). 948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlag_InitRes = 0x2 958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}; 968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comREGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned) 998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comREGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool) 1008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// \brief A call receiving a reference to 'self' invalidates the object that 1028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// 'self' contains. This keeps the "self flags" assigned to the 'self' 1038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// object before the call so we can assign them to the new object that 'self' 1048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// points to after the call. 1058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comREGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned) 1068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) { 1088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (SymbolRef sym = val.getAsSymbol()) 1098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (const unsigned *attachedFlags = state->get<SelfFlag>(sym)) 1108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return (SelfFlagEnum)*attachedFlags; 1118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SelfFlag_None; 1128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) { 1158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return getSelfFlags(val, C.getState()); 1168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic void addSelfFlag(ProgramStateRef state, SVal val, 1198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlagEnum flag, CheckerContext &C) { 1208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // We tag the symbol that the SVal wraps. 1218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (SymbolRef sym = val.getAsSymbol()) { 1228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag); 1238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.addTransition(state); 1248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 1258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) { 1288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return getSelfFlags(val, C) & flag; 1298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// \brief Returns true of the value of the expression is the object that 'self' 1328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// points to and is an object that did not come from the result of calling 1338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// an initializer. 1348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isInvalidSelf(const Expr *E, CheckerContext &C) { 1358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SVal exprVal = C.getState()->getSVal(E, C.getLocationContext()); 1368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!hasSelfFlag(exprVal, SelfFlag_Self, C)) 1378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; // value did not come from 'self'. 1388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (hasSelfFlag(exprVal, SelfFlag_InitRes, C)) 1398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; // 'self' is properly initialized. 1408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return true; 1428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C, 1458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const char *errorStr) const { 1468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!E) 1478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!C.getState()->get<CalledInit>()) 1508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!isInvalidSelf(E, C)) 1538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Generate an error node. 1568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ExplodedNode *N = C.generateSink(); 1578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!N) 1588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!BT) 1618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"", 1628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com categories::CoreFoundationObjectiveC)); 1638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com BugReport *report = new BugReport(*BT, errorStr, N); 1648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.emitReport(report); 1658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, 1688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 1698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // When encountering a message that does initialization (init rule), 1708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // tag the return value so that we know later on that if self has this value 1718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // then it is properly initialized. 1728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME: A callback should disable checkers at the start of functions. 1748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 1758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 1768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (isInitMessage(Msg)) { 1798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Tag the return value as the result of an initializer. 1808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ProgramStateRef state = C.getState(); 1818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME this really should be context sensitive, where we record 1838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // the current stack frame (for IPA). Also, we need to clean this 1848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // value out when we return from this method. 1858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com state = state->set<CalledInit>(true); 1868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SVal V = state->getSVal(Msg.getOriginExpr(), C.getLocationContext()); 1888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com addSelfFlag(state, V, SelfFlag_InitRes, C); 1898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 1908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 1918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // We don't check for an invalid 'self' in an obj-c message expression to cut 1938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // down false positives where logging functions get information from self 1948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // (like its class) or doing "invalidation" on self when the initialization 1958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // fails. 1968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E, 1998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 2008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME: A callback should disable checkers at the start of functions. 2018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 2028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 2038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com checkForInvalidSelf( 2068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com E->getBase(), C, 2078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Instance variable used while 'self' is not set to the result of " 2088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "'[(super or self) init...]'"); 2098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, 2128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 2138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME: A callback should disable checkers at the start of functions. 2148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 2158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 2168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com checkForInvalidSelf(S->getRetValue(), C, 2198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Returning 'self' while it is not set to the result of " 2208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "'[(super or self) init...]'"); 2218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// When a call receives a reference to 'self', [Pre/Post]Call pass 2248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// the SelfFlags from the object 'self' points to before the call to the new 2258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// object after the call. This is to avoid invalidation of 'self' by logging 2268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// functions. 2278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Another common pattern in classes with multiple initializers is to put the 2288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// subclass's common initialization bits into a static function that receives 2298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// the value of 'self', e.g: 2308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// @code 2318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// if (!(self = [super init])) 2328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// return nil; 2338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// if (!(self = _commonInit(self))) 2348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// return nil; 2358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// @endcode 2368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Until we can use inter-procedural analysis, in such a call, transfer the 2378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// SelfFlags to the result of the call. 2388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkPreCall(const CallEvent &CE, 2408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 2418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME: A callback should disable checkers at the start of functions. 2428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 2438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 2448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ProgramStateRef state = C.getState(); 2478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unsigned NumArgs = CE.getNumArgs(); 2488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // If we passed 'self' as and argument to the call, record it in the state 2498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // to be propagated after the call. 2508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Note, we could have just given up, but try to be more optimistic here and 2518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // assume that the functions are going to continue initialization or will not 2528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // modify self. 2538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (unsigned i = 0; i < NumArgs; ++i) { 2548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SVal argV = CE.getArgSVal(i); 2558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (isSelfVar(argV, C)) { 2568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unsigned selfFlags = getSelfFlags(state->getSVal(argV.castAs<Loc>()), C); 2578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); 2588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 2608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unsigned selfFlags = getSelfFlags(argV, C); 2618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.addTransition(state->set<PreCallSelfFlags>(selfFlags)); 2628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkPostCall(const CallEvent &CE, 2688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 2698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // FIXME: A callback should disable checkers at the start of functions. 2708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 2718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 2728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ProgramStateRef state = C.getState(); 2758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>(); 2768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!prevFlags) 2778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com state = state->remove<PreCallSelfFlags>(); 2798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unsigned NumArgs = CE.getNumArgs(); 2818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (unsigned i = 0; i < NumArgs; ++i) { 2828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SVal argV = CE.getArgSVal(i); 2838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (isSelfVar(argV, C)) { 2848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // If the address of 'self' is being passed to the call, assume that the 2858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // 'self' after the call will have the same flags. 2868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // EX: log(&self) 2878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C); 2888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { 2908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // If 'self' is passed to the call by value, assume that the function 2918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // returns 'self'. So assign the flags, which were set on 'self' to the 2928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // return value. 2938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // EX: self = performMoreInitialization(self) 2948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com addSelfFlag(state, CE.getReturnValue(), prevFlags, C); 2958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 2968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.addTransition(state); 3008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad, 3038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const Stmt *S, 3048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 3058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( 3068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.getCurrentAnalysisDeclContext()->getDecl()))) 3078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 3088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Tag the result of a load from 'self' so that we can easily know that the 3108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // value is the object that 'self' points to. 3118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ProgramStateRef state = C.getState(); 3128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (isSelfVar(location, C)) 3138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self, 3148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C); 3158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S, 3198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com CheckerContext &C) const { 3208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Allow assignment of anything to self. Self is a local variable in the 3218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // initializer, so it is legal to assign anything to it, like results of 3228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // static functions/method calls. After self is assigned something we cannot 3238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // reason about, stop enforcing the rules. 3248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // (Only continue checking if the assigned value should be treated as self.) 3258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if ((isSelfVar(loc, C)) && 3268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com !hasSelfFlag(val, SelfFlag_InitRes, C) && 3278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com !hasSelfFlag(val, SelfFlag_Self, C) && 3288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com !isSelfVar(val, C)) { 3298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Stop tracking the checker-specific state in the state. 3318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ProgramStateRef State = C.getState(); 3328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com State = State->remove<CalledInit>(); 3338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (SymbolRef sym = loc.getAsSymbol()) 3348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com State = State->remove<SelfFlag>(sym); 3358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com C.addTransition(State); 3368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State, 3408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const char *NL, const char *Sep) const { 3418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlagTy FlagMap = State->get<SelfFlag>(); 3428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com bool DidCallInit = State->get<CalledInit>(); 3438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>(); 3448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags) 3468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return; 3478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << Sep << NL << *this << " :" << NL; 3498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (DidCallInit) 3518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << " An init method has been called." << NL; 3528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (PreCallFlags != SelfFlag_None) { 3548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (PreCallFlags & SelfFlag_Self) { 3558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << " An argument of the current call came from the 'self' variable." 3568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com << NL; 3578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (PreCallFlags & SelfFlag_InitRes) { 3598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << " An argument of the current call came from an init method." 3608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com << NL; 3618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << NL; 3658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end(); 3668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com I != E; ++I) { 3678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << I->first << " : "; 3688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (I->second == SelfFlag_None) 3708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << "none"; 3718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (I->second & SelfFlag_Self) 3738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << "self variable"; 3748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (I->second & SelfFlag_InitRes) { 3768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (I->second != SelfFlag_InitRes) 3778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << " | "; 3788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << "result of init method"; 3798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com Out << NL; 3828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// FIXME: A callback should disable checkers at the start of functions. 3878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { 3888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!ND) 3898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 3908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND); 3928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!MD) 3938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 3948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!isInitializationMethod(MD)) 3958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 3968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // self = [super init] applies only to NSObject subclasses. 3988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // For instance, NSProxy doesn't implement -init. 3998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ASTContext &Ctx = MD->getASTContext(); 4008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); 4018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass(); 4028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for ( ; ID ; ID = ID->getSuperClass()) { 4038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com IdentifierInfo *II = ID->getIdentifier(); 4048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (II == NSObjectII) 4068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com break; 4078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!ID) 4098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 4108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return true; 4128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com/// \brief Returns true if the location is 'self'. 4158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isSelfVar(SVal location, CheckerContext &C) { 4168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext(); 4178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!analCtx->getSelfDecl()) 4188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 4198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!location.getAs<loc::MemRegionVal>()) 4208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 4218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>(); 4238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts())) 4248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return (DR->getDecl() == analCtx->getSelfDecl()); 4258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 4278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isInitializationMethod(const ObjCMethodDecl *MD) { 4308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return MD->getMethodFamily() == OMF_init; 4318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstatic bool isInitMessage(const ObjCMethodCall &Call) { 4348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return Call.getMethodFamily() == OMF_init; 4358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com//===----------------------------------------------------------------------===// 4388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Registration. 4398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com//===----------------------------------------------------------------------===// 4408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid ento::registerObjCSelfInitChecker(CheckerManager &mgr) { 4428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com mgr.registerChecker<ObjCSelfInitChecker>(); 4438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com