ExprEngineObjC.cpp [plain text]
#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar;
StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
}
void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
}
void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const Stmt *elem = S->getElement();
ProgramStateRef state = Pred->getState();
SVal elementV;
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
assert(elemD->getInit() == 0);
elementV = state->getLValue(elemD, Pred->getLocationContext());
}
else {
elementV = state->getSVal(elem, Pred->getLocationContext());
}
ExplodedNodeSet dstLocation;
evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
Pred = *NI;
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
SVal TrueV = svalBuilder.makeTruthVal(1);
ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
SVal FalseV = svalBuilder.makeTruthVal(0);
ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
if (const TypedValueRegion *R =
dyn_cast<TypedValueRegion>(MV->getRegion())) {
QualType T = R->getValueType();
assert(Loc::isLocType(T));
SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
currBldrCtx->blockCount());
SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V);
SVal nilV = svalBuilder.makeIntVal(0, T);
noElems = noElems->bindLoc(elementV, nilV);
}
Bldr.generateNode(S, Pred, hasElems);
Bldr.generateNode(S, Pred, noElems);
}
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
}
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<ObjCMethodCall> Msg =
CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
*Msg, *this);
ExplodedNodeSet dstGenericPrevisit;
getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
*Msg, *this);
ExplodedNodeSet dstEval;
StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
ProgramStateRef State = Pred->getState();
CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
if (UpdatedMsg->isInstanceMessage()) {
SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = State->assume(receiverVal);
if (nilState && !notNilState) {
continue;
}
assert(notNilState);
if (ObjCNoRet.isImplicitNoReturn(ME)) {
Bldr.generateSink(currStmt, Pred, State);
continue;
}
if (notNilState != State) {
Pred = Bldr.generateNode(currStmt, Pred, notNilState);
assert(Pred && "Should have cached out already!");
}
}
} else {
if (ObjCNoRet.isImplicitNoReturn(ME)) {
Bldr.generateSink(currStmt, Pred, Pred->getState());
continue;
}
}
defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
ExplodedNodeSet dstPostvisit;
getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
*Msg, *this);
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
*Msg, *this);
}