47 #include "llvm/Support/raw_ostream.h" 49 using namespace clang;
55 static bool isSelfVar(SVal location, CheckerContext &C);
58 class ObjCSelfInitChecker :
public Checker< check::PostObjCMessage,
59 check::PostStmt<ObjCIvarRefExpr>,
60 check::PreStmt<ReturnStmt>,
65 mutable std::unique_ptr<BugType> BT;
67 void checkForInvalidSelf(
const Expr *E, CheckerContext &C,
68 const char *errorStr)
const;
71 ObjCSelfInitChecker() {}
72 void checkPostObjCMessage(
const ObjCMethodCall &Msg, CheckerContext &C)
const;
74 void checkPreStmt(
const ReturnStmt *S, CheckerContext &C)
const;
75 void checkLocation(SVal location,
bool isLoad,
const Stmt *S,
76 CheckerContext &C)
const;
77 void checkBind(SVal loc, SVal val,
const Stmt *S, CheckerContext &C)
const;
79 void checkPreCall(
const CallEvent &CE, CheckerContext &C)
const;
80 void checkPostCall(
const CallEvent &CE, CheckerContext &C)
const;
83 const char *NL,
const char *Sep)
const override;
94 SelfFlag_InitRes = 0x2
109 if (
const unsigned *attachedFlags =
state->get<SelfFlag>(sym))
111 return SelfFlag_None;
122 state = state->set<SelfFlag>(sym,
getSelfFlags(val, state) | flag);
123 C.addTransition(state);
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(llvm::make_unique<BugReport>(*BT, errorStr, N));
166 void ObjCSelfInitChecker::checkPostObjCMessage(
const ObjCMethodCall &Msg,
167 CheckerContext &C)
const {
174 C.getCurrentAnalysisDeclContext()->getDecl())))
184 state = state->set<CalledInit>(
true);
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())))
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 unsigned selfFlags =
getSelfFlags(state->getSVal(argV.castAs<Loc>()), C);
256 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
260 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
266 void ObjCSelfInitChecker::checkPostCall(
const CallEvent &CE,
267 CheckerContext &C)
const {
270 C.getCurrentAnalysisDeclContext()->getDecl())))
277 state = state->remove<PreCallSelfFlags>();
279 unsigned NumArgs = CE.getNumArgs();
280 for (
unsigned i = 0; i < NumArgs; ++i) {
281 SVal argV = CE.getArgSVal(i);
286 addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C);
293 addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
298 C.addTransition(state);
301 void ObjCSelfInitChecker::checkLocation(SVal location,
bool isLoad,
303 CheckerContext &C)
const {
305 C.getCurrentAnalysisDeclContext()->getDecl())))
312 addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self,
317 void ObjCSelfInitChecker::checkBind(SVal loc, SVal val,
const Stmt *S,
318 CheckerContext &C)
const {
331 State = State->remove<CalledInit>();
333 State = State->remove<SelfFlag>(sym);
334 C.addTransition(State);
339 const char *NL,
const char *Sep)
const {
340 SelfFlagTy FlagMap =
State->get<SelfFlag>();
341 bool DidCallInit =
State->get<CalledInit>();
344 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
347 Out << Sep << NL << *
this <<
" :" << NL;
350 Out <<
" An init method has been called." << NL;
352 if (PreCallFlags != SelfFlag_None) {
353 if (PreCallFlags & SelfFlag_Self) {
354 Out <<
" An argument of the current call came from the 'self' variable." 357 if (PreCallFlags & SelfFlag_InitRes) {
358 Out <<
" An argument of the current call came from an init method." 364 for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
366 Out << I->first <<
" : ";
368 if (I->second == SelfFlag_None)
371 if (I->second & SelfFlag_Self)
372 Out <<
"self variable";
374 if (I->second & SelfFlag_InitRes) {
375 if (I->second != SelfFlag_InitRes)
377 Out <<
"result of init method";
404 if (II == NSObjectII)
407 return ID !=
nullptr;
411 static bool isSelfVar(SVal location, CheckerContext &C) {
415 if (!location.getAs<loc::MemRegionVal>())
418 loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
419 if (
const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
437 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
438 mgr.registerChecker<ObjCSelfInitChecker>();
const char *const CoreFoundationObjectiveC
ObjCInterfaceDecl * getClassInterface()
const SymExpr * SymbolRef
Stmt - This represents one statement.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
ObjCMethodDecl - Represents an instance or class method declaration.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
static bool isInvalidSelf(const Expr *E, CheckerContext &C)
Returns true of the value of the expression is the object that 'self' points to and is an object that...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function or method under analysis.
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
static bool isInitMessage(const ObjCMethodCall &Msg)
static bool isInitializationMethod(const ObjCMethodDecl *MD)
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Represents any expression that calls an Objective-C method.
static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)
A call receiving a reference to 'self' invalidates the object that 'self' contains.
Represents an ObjC class declaration.
This represents one expression.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)
ObjCInterfaceDecl * getSuperClass() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
const ImplicitParamDecl * getSelfDecl() const
Return the ImplicitParamDecl* associated with 'self' if this AnalysisDeclContext wraps an ObjCMethodD...
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy...
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
ASTContext & getASTContext() const LLVM_READONLY
static bool isSelfVar(SVal location, CheckerContext &C)
Returns true if the location is 'self'.
virtual const ObjCMessageExpr * getOriginExpr() const
Dataflow Directional Tag Classes.
ObjCMethodFamily getMethodFamily() const
const Expr * getBase() const
ObjCIvarRefExpr - A reference to an ObjC instance variable.
This represents a decl that may have a name.