aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h93
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Core/Calls.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp22
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp36
10 files changed, 136 insertions, 80 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
index 1327c8971c..fdfb485a52 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
@@ -36,7 +36,10 @@ enum CallEventKind {
CE_CXXConstructor,
CE_BEG_FUNCTION_CALLS = CE_Function,
CE_END_FUNCTION_CALLS = CE_CXXConstructor,
- CE_ObjCMessage
+ CE_ObjCMessage,
+ CE_ObjCPropertyAccess,
+ CE_BEG_OBJC_CALLS = CE_ObjCMessage,
+ CE_END_OBJC_CALLS = CE_ObjCPropertyAccess
};
/// \brief Represents an abstract call to a function or method along a
@@ -318,17 +321,15 @@ public:
}
};
-/// \brief Represents any expression that causes an Objective-C message send.
-//
-// This class is mostly passthrough to ObjCMessage, because /that/ class is the
-// adapter for the different kinds of Objective-C messages in the system. The
-// difference here is that like other CallActions this refers to a specific
-// (path-sensitive) message send, while ObjCMessage is simply a wrapper for the
-// various (path-insensitive) expressions that are implemented using messages.
-class ObjCMessageInvocation : public CallEvent {
- ObjCMessage Msg;
+/// \brief Represents any expression that calls an Objective-C method.
+class ObjCMethodCall : public CallEvent {
+ const ObjCMessageExpr *Msg;
protected:
+ ObjCMethodCall(const ObjCMessageExpr *msg, ProgramStateRef St,
+ const LocationContext *LCtx, Kind K)
+ : CallEvent(St, LCtx, K), Msg(msg) {}
+
void addExtraInvalidatedRegions(RegionList &Regions) const;
param_iterator param_begin() const;
@@ -337,34 +338,78 @@ protected:
QualType getDeclaredResultType() const;
public:
- ObjCMessageInvocation(const ObjCMessage &msg, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(St, LCtx, CE_ObjCMessage), Msg(msg) {}
-
- Selector getSelector() const { return Msg.getSelector(); }
- bool isInstanceMessage() const { return Msg.isInstanceMessage(); }
- const ObjCMethodDecl *getDecl() const { return Msg.getMethodDecl(); }
- unsigned getNumArgs() const { return Msg.getNumArgs(); }
- const Expr *getArgExpr(unsigned Index) const { return Msg.getArgExpr(Index); }
+ Selector getSelector() const { return Msg->getSelector(); }
+ bool isInstanceMessage() const { return Msg->isInstanceMessage(); }
+ ObjCMethodFamily getMethodFamily() const { return Msg->getMethodFamily(); }
+ const ObjCMethodDecl *getDecl() const { return Msg->getMethodDecl(); }
+ unsigned getNumArgs() const { return Msg->getNumArgs(); }
+ const Expr *getArgExpr(unsigned Index) const {
+ return Msg->getArg(Index);
+ }
- // FIXME: for emitting warnings and such this may not be the best idea.
- const Expr *getOriginExpr() const { return Msg.getMessageExpr(); }
+ const ObjCMessageExpr *getOriginExpr() const { return Msg; }
SVal getReceiverSVal() const;
+ const ObjCInterfaceDecl *getReceiverInterface() const {
+ return Msg->getReceiverInterface();
+ }
+
SourceRange getReceiverSourceRange() const {
- return Msg.getReceiverSourceRange();
+ return Msg->getReceiverRange();
}
- const ObjCInterfaceDecl *getReceiverInterface() const {
- return Msg.getReceiverInterface();
+ // FIXME: Remove this once everything is converted to use ObjCMethodCall.
+ virtual operator ObjCMessage() const {
+ return ObjCMessage(Msg);
}
static bool classof(const CallEvent *CA) {
+ return CA->getKind() >= CE_BEG_OBJC_CALLS &&
+ CA->getKind() <= CE_END_OBJC_CALLS;
+ }
+};
+
+/// \brief Represents an explicit message send to an Objective-C object.
+///
+/// Example: [obj descriptionWithLocale:locale];
+class ObjCMessageSend : public ObjCMethodCall {
+public:
+ ObjCMessageSend(const ObjCMessageExpr *Msg, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : ObjCMethodCall(Msg, St, LCtx, CE_ObjCMessage) {}
+
+ static bool classof(const CallEvent *CA) {
return CA->getKind() == CE_ObjCMessage;
}
};
+/// \brief Represents an Objective-C property getter or setter invocation.
+///
+/// Example: obj.prop += 1;
+class ObjCPropertyAccess : public ObjCMethodCall {
+ const ObjCPropertyRefExpr *PropE;
+
+public:
+ ObjCPropertyAccess(const ObjCPropertyRefExpr *pe, const ObjCMessageExpr *Msg,
+ const ProgramStateRef St, const LocationContext *LCtx)
+ : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess), PropE(pe) {}
+
+ /// \brief Returns true if this property access is calling the setter method.
+ bool isSetter() const {
+ return getNumArgs() > 0;
+ }
+
+ // FIXME: Remove this once everything is converted to use ObjCMethodCall.
+ operator ObjCMessage() const {
+ return ObjCMessage(getOriginExpr(), PropE, isSetter());
+ }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_ObjCPropertyAccess;
+ }
+};
+
} // end namespace ento
} // end namespace clang
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 46fb70deae..bddc23cacd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -42,7 +42,7 @@ namespace ento {
class AnalysisManager;
class CallEvent;
-class ObjCMessage;
+class ObjCMethodCall;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -347,7 +347,7 @@ public:
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred,
+ void VisitObjCMessage(const ObjCMethodCall &Msg, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
@@ -433,7 +433,7 @@ public:
}
protected:
- void evalObjCMessage(StmtNodeBuilder &Bldr, const ObjCMessage &msg,
+ void evalObjCMessage(StmtNodeBuilder &Bldr, const ObjCMethodCall &Msg,
ExplodedNode *Pred, ProgramStateRef state,
bool GenSink);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index e567d2d498..f64326d2c6 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -53,7 +53,7 @@ public:
return IsPropSetter;
}
- const Expr *getMessageExpr() const {
+ const ObjCMessageExpr *getMessageExpr() const {
return Msg;
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 11a9ab373c..30be60c9a6 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -300,7 +300,8 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
"Argument for property setter is an uninitialized value"
: "Argument in message expression is an uninitialized value";
// Check for any arguments that are uninitialized/undefined.
- PreVisitProcessArgs(C, ObjCMessageInvocation(msg, state, LCtx),
+ // FIXME: ObjCMessage is set to be removed soon.
+ PreVisitProcessArgs(C, ObjCMessageSend(msg.getMessageExpr(), state, LCtx),
bugDesc, BT_msg_arg);
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 29bb9c8f25..2c960921a4 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -481,8 +481,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
C.addTransition(State);
}
-static bool isFreeWhenDoneSetToZero(const ObjCMessageInvocation &Call,
- Selector &S) {
+static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
+ Selector S = Call.getSelector();
for (unsigned i = 1; i < S.getNumArgs(); ++i)
if (S.getNameForSlot(i).equals("freeWhenDone"))
if (Call.getArgSVal(i).isConstant(0))
@@ -497,7 +497,9 @@ void MallocChecker::checkPreObjCMessage(const ObjCMessage &Msg,
if (!MD)
return;
- ObjCMessageInvocation Call(Msg, C.getState(), C.getLocationContext());
+ // FIXME: ObjCMessage is going away soon.
+ ObjCMessageSend Call(Msg.getMessageExpr(), C.getState(),
+ C.getLocationContext());
Selector S = Msg.getSelector();
// If the first selector is dataWithBytesNoCopy, assume that the memory will
@@ -508,7 +510,7 @@ void MallocChecker::checkPreObjCMessage(const ObjCMessage &Msg,
if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
- !isFreeWhenDoneSetToZero(Call, S)){
+ !isFreeWhenDoneSetToZero(Call)){
unsigned int argIdx = 0;
C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx),
Msg.getMessageExpr(), C.getState(), true));
@@ -1322,11 +1324,11 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
// TODO: If we want to be more optimistic here, we'll need to make sure that
// regions escape to C++ containers. They seem to do that even now, but for
// mysterious reasons.
- if (!(isa<FunctionCall>(Call) || isa<ObjCMessageInvocation>(Call)))
+ if (!(isa<FunctionCall>(Call) || isa<ObjCMethodCall>(Call)))
return false;
// Check Objective-C messages by selector name.
- if (const ObjCMessageInvocation *Msg = dyn_cast<ObjCMessageInvocation>(Call)){
+ if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
// If it's not a framework call, or if it takes a callback, assume it
// can free memory.
if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg())
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index bb6ab6f2e3..c25da87405 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -209,7 +209,9 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
return;
}
- ObjCMessageInvocation MsgWrapper(msg, C.getState(), C.getLocationContext());
+ // FIXME: ObjCMessage is going away.
+ ObjCMessageSend MsgWrapper(msg.getMessageExpr(), C.getState(),
+ C.getLocationContext());
checkPostStmt(MsgWrapper, C);
// We don't check for an invalid 'self' in an obj-c message expression to cut
@@ -300,7 +302,9 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
void ObjCSelfInitChecker::checkPreObjCMessage(ObjCMessage Msg,
CheckerContext &C) const {
- ObjCMessageInvocation MsgWrapper(Msg, C.getState(), C.getLocationContext());
+ // FIXME: ObjCMessage is going away.
+ ObjCMessageSend MsgWrapper(Msg.getMessageExpr(), C.getState(),
+ C.getLocationContext());
checkPreStmt(MsgWrapper, C);
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index d43b2cde26..12b74e7e29 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -747,10 +747,10 @@ public:
QualType RetTy,
ObjCMethodSummariesTy &CachedSummaries);
- const RetainSummary *getInstanceMethodSummary(const ObjCMessageInvocation &M,
+ const RetainSummary *getInstanceMethodSummary(const ObjCMethodCall &M,
ProgramStateRef State);
- const RetainSummary *getClassMethodSummary(const ObjCMessageInvocation &M) {
+ const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) {
assert(!M.isInstanceMessage());
const ObjCInterfaceDecl *Class = M.getReceiverInterface();
@@ -950,8 +950,9 @@ RetainSummaryManager::getSummary(const CallEvent &Call,
case CE_CXXConstructor:
// FIXME: These calls are currently unsupported.
return getPersistentStopSummary();
- case CE_ObjCMessage: {
- const ObjCMessageInvocation &Msg = cast<ObjCMessageInvocation>(Call);
+ case CE_ObjCMessage:
+ case CE_ObjCPropertyAccess: {
+ const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
if (Msg.isInstanceMessage())
Summ = getInstanceMethodSummary(Msg, State);
else
@@ -1447,7 +1448,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
}
const RetainSummary *
-RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageInvocation &Msg,
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMethodCall &Msg,
ProgramStateRef State) {
const ObjCInterfaceDecl *ReceiverClass = 0;
@@ -2795,7 +2796,8 @@ void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
const LocationContext *LC = C.getLocationContext();
- ObjCMessageInvocation Call(Msg, state, LC);
+ // FIXME: ObjCMessage is going away.
+ ObjCMessageSend Call(Msg.getMessageExpr(), state, LC);
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ = Summaries.getSummary(Call, state);
@@ -2859,8 +2861,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
// Evaluate the effect on the message receiver.
bool ReceiverIsTracked = false;
if (!hasErr) {
- const ObjCMessageInvocation *MsgInvocation =
- dyn_cast<ObjCMessageInvocation>(&CallOrMsg);
+ const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg);
if (MsgInvocation) {
if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
if (const RefVal *T = state->get<RefBindings>(Sym)) {
diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp
index 510f8340a2..bdd4508cea 100644
--- a/lib/StaticAnalyzer/Core/Calls.cpp
+++ b/lib/StaticAnalyzer/Core/Calls.cpp
@@ -334,7 +334,7 @@ void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
}
-CallEvent::param_iterator ObjCMessageInvocation::param_begin() const {
+CallEvent::param_iterator ObjCMethodCall::param_begin() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
return 0;
@@ -342,7 +342,7 @@ CallEvent::param_iterator ObjCMessageInvocation::param_begin() const {
return D->param_begin();
}
-CallEvent::param_iterator ObjCMessageInvocation::param_end() const {
+CallEvent::param_iterator ObjCMethodCall::param_end() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
return 0;
@@ -351,12 +351,12 @@ CallEvent::param_iterator ObjCMessageInvocation::param_end() const {
}
void
-ObjCMessageInvocation::addExtraInvalidatedRegions(RegionList &Regions) const {
+ObjCMethodCall::addExtraInvalidatedRegions(RegionList &Regions) const {
if (const MemRegion *R = getReceiverSVal().getAsRegion())
Regions.push_back(R);
}
-QualType ObjCMessageInvocation::getDeclaredResultType() const {
+QualType ObjCMethodCall::getDeclaredResultType() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
return QualType();
@@ -364,12 +364,12 @@ QualType ObjCMessageInvocation::getDeclaredResultType() const {
return D->getResultType();
}
-SVal ObjCMessageInvocation::getReceiverSVal() const {
+SVal ObjCMethodCall::getReceiverSVal() const {
// FIXME: Is this the best way to handle class receivers?
if (!isInstanceMessage())
return UnknownVal();
- const Expr *Base = Msg.getInstanceReceiver();
+ const Expr *Base = Msg->getInstanceReceiver();
if (Base)
return getSVal(Base);
@@ -377,5 +377,6 @@ SVal ObjCMessageInvocation::getReceiverSVal() const {
// In this case the object reference is the same as 'self'.
const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
- return loc::MemRegionVal(State->getRegion(SelfDecl, LCtx));
+ return State->getSVal(State->getRegion(SelfDecl, LCtx));
}
+
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 255d870186..141c5bbf03 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -867,26 +867,32 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ObjCMessageExprClass: {
Bldr.takeNodes(Pred);
// Is this a property access?
- const ParentMap &PM = Pred->getLocationContext()->getParentMap();
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const ParentMap &PM = LCtx->getParentMap();
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(S);
bool evaluated = false;
if (const PseudoObjectExpr *PO =
- dyn_cast_or_null<PseudoObjectExpr>(PM.getParent(S))) {
+ dyn_cast_or_null<PseudoObjectExpr>(PM.getParent(S))) {
const Expr *syntactic = PO->getSyntacticForm();
+
+ // This handles the funny case of assigning to the result of a getter.
+ // This can happen if the getter returns a non-const reference.
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(syntactic))
+ syntactic = BO->getLHS();
+
if (const ObjCPropertyRefExpr *PR =
dyn_cast<ObjCPropertyRefExpr>(syntactic)) {
- bool isSetter = ME->getNumArgs() > 0;
- VisitObjCMessage(ObjCMessage(ME, PR, isSetter), Pred, Dst);
+ VisitObjCMessage(ObjCPropertyAccess(PR, ME, Pred->getState(), LCtx),
+ Pred, Dst);
evaluated = true;
}
- else if (isa<BinaryOperator>(syntactic)) {
- VisitObjCMessage(ObjCMessage(ME, 0, true), Pred, Dst);
- }
}
if (!evaluated)
- VisitObjCMessage(ME, Pred, Dst);
+ VisitObjCMessage(ObjCMessageSend(ME, Pred->getState(), LCtx),
+ Pred, Dst);
Bldr.addNodes(Dst);
break;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index d35d999b5e..86630a8c02 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -141,7 +141,7 @@ static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
return isSubclass(Class->getSuperClass(), II);
}
-void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
+void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
@@ -160,18 +160,20 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
ExplodedNode *Pred = *DI;
bool RaisesException = false;
- if (const Expr *Receiver = msg.getInstanceReceiver()) {
- ProgramStateRef state = Pred->getState();
- SVal recVal = state->getSVal(Receiver, Pred->getLocationContext());
+ if (msg.isInstanceMessage()) {
+ SVal recVal = msg.getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+ ProgramStateRef state = Pred->getState();
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = state->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
+ // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
+ // Revisit once we have lazier constraints.
if (nilState && !notNilState) {
continue;
}
@@ -186,12 +188,9 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
// Dispatch to plug-in transfer function.
evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
}
- } else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
- // Note that this branch also handles messages to super, not just
- // class methods!
-
+ } else {
// Check for special class methods.
- if (!msg.isInstanceMessage()) {
+ if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
if (!NSExceptionII) {
ASTContext &Ctx = getContext();
NSExceptionII = &Ctx.Idents.get("NSException");
@@ -243,13 +242,10 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
}
void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
ExplodedNode *Pred,
ProgramStateRef state,
bool GenSink) {
- const LocationContext *LCtx = Pred->getLocationContext();
- unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
-
// First handle the return value.
SVal ReturnValue = UnknownVal();
@@ -261,17 +257,18 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
case OMF_retain:
case OMF_self: {
// These methods return their receivers.
- const Expr *ReceiverE = msg.getInstanceReceiver();
- if (ReceiverE)
- ReturnValue = state->getSVal(ReceiverE, LCtx);
+ ReturnValue = msg.getReceiverSVal();
break;
}
}
+ const LocationContext *LCtx = Pred->getLocationContext();
+ unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
+
// If we failed to figure out the return value, use a conjured value instead.
if (ReturnValue.isUnknown()) {
SValBuilder &SVB = getSValBuilder();
- QualType ResultTy = msg.getResultType(getContext());
+ QualType ResultTy = msg.getResultType();
const Expr *CurrentE = cast<Expr>(currentStmt);
ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy,
BlockCount);
@@ -281,11 +278,10 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
state = state->BindExpr(currentStmt, LCtx, ReturnValue);
// Invalidate the arguments (and the receiver)
- ObjCMessageInvocation Invocation(msg, state, LCtx);
- state = Invocation.invalidateRegions(BlockCount);
+ state = msg.invalidateRegions(BlockCount, state);
// And create the new node.
- Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
+ Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink);
assert(Bldr.hasGeneratedNodes());
}