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 unsigned *attachedFlags =
state->get<SelfFlag>(sym))
110 return SelfFlag_None;
121 state = state->set<SelfFlag>(sym,
getSelfFlags(val, state) | flag);
122 C.addTransition(state);
134 SVal exprVal = C.getSVal(E);
143 void ObjCSelfInitChecker::checkForInvalidSelf(
const Expr *E, CheckerContext &C,
144 const char *errorStr)
const {
148 if (!C.getState()->get<CalledInit>())
155 ExplodedNode *N = C.generateErrorNode();
160 BT.reset(
new BugType(
this,
"Missing \"self = [(super or self) init...]\"",
162 C.emitReport(llvm::make_unique<BugReport>(*BT, errorStr, N));
165 void ObjCSelfInitChecker::checkPostObjCMessage(
const ObjCMethodCall &Msg,
166 CheckerContext &C)
const {
173 C.getCurrentAnalysisDeclContext()->getDecl())))
183 state = state->set<CalledInit>(
true);
197 CheckerContext &C)
const {
200 C.getCurrentAnalysisDeclContext()->getDecl())))
205 "Instance variable used while 'self' is not set to the result of " 206 "'[(super or self) init...]'");
209 void ObjCSelfInitChecker::checkPreStmt(
const ReturnStmt *S,
210 CheckerContext &C)
const {
213 C.getCurrentAnalysisDeclContext()->getDecl())))
217 "Returning 'self' while it is not set to the result of " 218 "'[(super or self) init...]'");
237 void ObjCSelfInitChecker::checkPreCall(
const CallEvent &CE,
238 CheckerContext &C)
const {
241 C.getCurrentAnalysisDeclContext()->getDecl())))
245 unsigned NumArgs = CE.getNumArgs();
251 for (
unsigned i = 0;
i < NumArgs; ++
i) {
252 SVal argV = CE.getArgSVal(
i);
254 unsigned selfFlags =
getSelfFlags(state->getSVal(argV.castAs<Loc>()), C);
255 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
259 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
265 void ObjCSelfInitChecker::checkPostCall(
const CallEvent &CE,
266 CheckerContext &C)
const {
269 C.getCurrentAnalysisDeclContext()->getDecl())))
276 state = state->remove<PreCallSelfFlags>();
278 unsigned NumArgs = CE.getNumArgs();
279 for (
unsigned i = 0;
i < NumArgs; ++
i) {
280 SVal argV = CE.getArgSVal(
i);
285 addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C);
292 addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
297 C.addTransition(state);
300 void ObjCSelfInitChecker::checkLocation(SVal location,
bool isLoad,
302 CheckerContext &C)
const {
304 C.getCurrentAnalysisDeclContext()->getDecl())))
311 addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self,
316 void ObjCSelfInitChecker::checkBind(SVal loc, SVal val,
const Stmt *S,
317 CheckerContext &C)
const {
330 State = State->remove<CalledInit>();
332 State = State->remove<SelfFlag>(sym);
333 C.addTransition(State);
338 const char *NL,
const char *Sep)
const {
339 SelfFlagTy FlagMap =
State->get<SelfFlag>();
340 bool DidCallInit =
State->get<CalledInit>();
343 if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
346 Out << Sep << NL << *
this <<
" :" << NL;
349 Out <<
" An init method has been called." << NL;
351 if (PreCallFlags != SelfFlag_None) {
352 if (PreCallFlags & SelfFlag_Self) {
353 Out <<
" An argument of the current call came from the 'self' variable." 356 if (PreCallFlags & SelfFlag_InitRes) {
357 Out <<
" An argument of the current call came from an init method." 363 for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
365 Out << I->first <<
" : ";
367 if (I->second == SelfFlag_None)
370 if (I->second & SelfFlag_Self)
371 Out <<
"self variable";
373 if (I->second & SelfFlag_InitRes) {
374 if (I->second != SelfFlag_InitRes)
376 Out <<
"result of init method";
403 if (II == NSObjectII)
406 return ID !=
nullptr;
410 static bool isSelfVar(SVal location, CheckerContext &C) {
414 if (!location.getAs<loc::MemRegionVal>())
417 loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
418 if (
const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
436 void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
437 mgr.registerChecker<ObjCSelfInitChecker>();
440 bool ento::shouldRegisterObjCSelfInitChecker(
const LangOptions &LO) {
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.