46#include "llvm/Support/raw_ostream.h"
57class ObjCSelfInitChecker :
public Checker< check::PostObjCMessage,
58 check::PostStmt<ObjCIvarRefExpr>,
59 check::PreStmt<ReturnStmt>,
64 mutable std::unique_ptr<BugType> BT;
67 const char *errorStr)
const;
70 ObjCSelfInitChecker() {}
74 void checkLocation(
SVal location,
bool isLoad,
const Stmt *S,
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;
121 state = state->set<SelfFlag>(sym,
123 C.addTransition(state);
135 SVal exprVal =
C.getSVal(E);
145 const char *errorStr)
const {
149 if (!
C.getState()->get<CalledInit>())
161 BT.reset(
new BugType(
this,
"Missing \"self = [(super or self) init...]\"",
163 C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, errorStr, N));
166void ObjCSelfInitChecker::checkPostObjCMessage(
const ObjCMethodCall &Msg,
174 C.getCurrentAnalysisDeclContext()->getDecl())))
184 state = state->set<CalledInit>(
true);
201 C.getCurrentAnalysisDeclContext()->getDecl())))
206 "Instance variable used while 'self' is not set to the result of "
207 "'[(super or self) init...]'");
210void ObjCSelfInitChecker::checkPreStmt(
const ReturnStmt *S,
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...]'");
238void ObjCSelfInitChecker::checkPreCall(
const CallEvent &CE,
242 C.getCurrentAnalysisDeclContext()->getDecl())))
252 for (
unsigned i = 0; i < NumArgs; ++i) {
255 SelfFlagEnum selfFlags =
257 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
261 C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
267void ObjCSelfInitChecker::checkPostCall(
const CallEvent &CE,
271 C.getCurrentAnalysisDeclContext()->getDecl())))
275 SelfFlagEnum prevFlags = state->get<PreCallSelfFlags>();
278 state = state->remove<PreCallSelfFlags>();
281 for (
unsigned i = 0; i < NumArgs; ++i) {
299 C.addTransition(state);
302void ObjCSelfInitChecker::checkLocation(
SVal location,
bool isLoad,
306 C.getCurrentAnalysisDeclContext()->getDecl())))
318void ObjCSelfInitChecker::checkBind(
SVal loc,
SVal val,
const Stmt *S,
332 State = State->remove<CalledInit>();
334 State = State->remove<SelfFlag>(sym);
335 C.addTransition(State);
339void ObjCSelfInitChecker::printState(raw_ostream &Out,
ProgramStateRef State,
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 (
auto [Sym, Flag] : FlagMap) {
368 if (Flag == SelfFlag_None)
371 if (Flag & SelfFlag_Self)
372 Out <<
"self variable";
374 if (Flag & SelfFlag_InitRes) {
375 if (Flag != SelfFlag_InitRes)
377 Out <<
"result of init method";
401 for ( ; ID ; ID = ID->getSuperClass()) {
404 if (II == NSObjectII)
407 return ID !=
nullptr;
415 if (!isa<loc::MemRegionVal>(location))
441bool ento::shouldRegisterObjCSelfInitChecker(
const CheckerManager &mgr) {
static bool isInitMessage(const ObjCMethodCall &Msg)
static bool isSelfVar(SVal location, CheckerContext &C)
Returns true if the location is 'self'.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND)
static bool isInitializationMethod(const ObjCMethodDecl *MD)
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...
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state)
A call receiving a reference to 'self' invalidates the object that 'self' contains.
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C)
static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
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, method or block under analysis.
const ImplicitParamDecl * getSelfDecl() const
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
This represents a decl that may have a name.
Represents an ObjC class declaration.
ObjCInterfaceDecl * getSuperClass() const
ObjCIvarRefExpr - A reference to an ObjC instance variable.
const Expr * getBase() const
ObjCMethodDecl - Represents an instance or class method declaration.
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
ObjCInterfaceDecl * getClassInterface()
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Stmt - This represents one statement.
Represents an abstract call to a function or method along a particular path.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
Represents any expression that calls an Objective-C method.
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * stripCasts(bool StripBaseCasts=true) const
Get the underlining region and strip casts.
const char *const CoreFoundationObjectiveC