46 #include "llvm/Support/raw_ostream.h"
48 using namespace clang;
54 static bool isSelfVar(SVal location, CheckerContext &C);
57 class ObjCSelfInitChecker :
public Checker< check::PostObjCMessage,
58 check::PostStmt<ObjCIvarRefExpr>,
59 check::PreStmt<ReturnStmt>,
64 mutable std::unique_ptr<BugType> BT;
66 void checkForInvalidSelf(
const Expr *E, CheckerContext &C,
67 const char *errorStr)
const;
70 ObjCSelfInitChecker() {}
71 void checkPostObjCMessage(
const ObjCMethodCall &Msg, CheckerContext &C)
const;
73 void checkPreStmt(
const ReturnStmt *S, CheckerContext &C)
const;
74 void checkLocation(SVal location,
bool isLoad,
const Stmt *S,
75 CheckerContext &C)
const;
76 void checkBind(SVal loc, SVal val,
const Stmt *S, CheckerContext &C)
const;
78 void checkPreCall(
const CallEvent &CE, CheckerContext &C)
const;
79 void checkPostCall(
const CallEvent &CE, CheckerContext &C)
const;
82 const char *NL,
const char *Sep)
const override;
93 SelfFlag_InitRes = 0x2
108 if (
const SelfFlagEnum *attachedFlags =
state->get<SelfFlag>(sym))
109 return *attachedFlags;
110 return SelfFlag_None;
118 SelfFlagEnum flag, CheckerContext &C) {
123 C.addTransition(
state);
127 static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
135 SVal exprVal = C.getSVal(E);
144 void ObjCSelfInitChecker::checkForInvalidSelf(
const Expr *E, CheckerContext &C,
145 const char *errorStr)
const {
149 if (!
C.getState()->get<CalledInit>())
156 ExplodedNode *N =
C.generateErrorNode();
161 BT.reset(
new BugType(
this,
"Missing \"self = [(super or self) init...]\"",
163 C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, errorStr, N));
166 void ObjCSelfInitChecker::checkPostObjCMessage(
const ObjCMethodCall &Msg,
167 CheckerContext &C)
const {
174 C.getCurrentAnalysisDeclContext()->getDecl())))
186 SVal
V =
C.getSVal(Msg.getOriginExpr());
198 CheckerContext &C)
const {
201 C.getCurrentAnalysisDeclContext()->getDecl())))
206 "Instance variable used while 'self' is not set to the result of "
207 "'[(super or self) init...]'");
210 void ObjCSelfInitChecker::checkPreStmt(
const ReturnStmt *S,
211 CheckerContext &C)
const {
214 C.getCurrentAnalysisDeclContext()->getDecl())))
217 checkForInvalidSelf(S->getRetValue(), C,
218 "Returning 'self' while it is not set to the result of "
219 "'[(super or self) init...]'");
238 void ObjCSelfInitChecker::checkPreCall(
const CallEvent &CE,
239 CheckerContext &C)
const {
242 C.getCurrentAnalysisDeclContext()->getDecl())))
246 unsigned NumArgs = CE.getNumArgs();
252 for (
unsigned i = 0; i < NumArgs; ++i) {
253 SVal argV = CE.getArgSVal(i);
255 SelfFlagEnum selfFlags =
257 C.addTransition(
state->set<PreCallSelfFlags>(selfFlags));
261 C.addTransition(
state->set<PreCallSelfFlags>(selfFlags));
267 void ObjCSelfInitChecker::checkPostCall(
const CallEvent &CE,
268 CheckerContext &C)
const {
271 C.getCurrentAnalysisDeclContext()->getDecl())))
275 SelfFlagEnum prevFlags =
state->get<PreCallSelfFlags>();
280 unsigned NumArgs = CE.getNumArgs();
281 for (
unsigned i = 0; i < NumArgs; ++i) {
282 SVal argV = CE.getArgSVal(i);
302 void ObjCSelfInitChecker::checkLocation(SVal location,
bool isLoad,
304 CheckerContext &C)
const {
306 C.getCurrentAnalysisDeclContext()->getDecl())))
318 void ObjCSelfInitChecker::checkBind(SVal loc, SVal val,
const Stmt *S,
319 CheckerContext &C)
const {
340 const char *NL,
const char *Sep)
const {
341 SelfFlagTy FlagMap =
State->get<SelfFlag>();
342 bool DidCallInit =
State->get<CalledInit>();
343 SelfFlagEnum PreCallFlags =
State->get<PreCallSelfFlags>();
345 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
348 Out << Sep << NL << *
this <<
" :" << NL;
351 Out <<
" An init method has been called." << NL;
353 if (PreCallFlags != SelfFlag_None) {
354 if (PreCallFlags & SelfFlag_Self) {
355 Out <<
" An argument of the current call came from the 'self' variable."
358 if (PreCallFlags & SelfFlag_InitRes) {
359 Out <<
" An argument of the current call came from an init method."
365 for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
367 Out << I->first <<
" : ";
369 if (I->second == SelfFlag_None)
372 if (I->second & SelfFlag_Self)
373 Out <<
"self variable";
375 if (I->second & SelfFlag_InitRes) {
376 if (I->second != SelfFlag_InitRes)
378 Out <<
"result of init method";
402 for ( ;
ID ;
ID =
ID->getSuperClass()) {
405 if (II == NSObjectII)
408 return ID !=
nullptr;
412 static bool isSelfVar(SVal location, CheckerContext &C) {
416 if (!isa<loc::MemRegionVal>(location))
419 loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
420 if (
const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
431 return Call.getMethodFamily() ==
OMF_init;
438 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
439 mgr.registerChecker<ObjCSelfInitChecker>();
442 bool ento::shouldRegisterObjCSelfInitChecker(
const CheckerManager &mgr) {