From cde8cdbd6a662c636164465ad309b5f17ff01064 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Mon, 2 Jul 2012 19:27:56 +0000 Subject: [PATCH] [analyzer] Begin replacing ObjCMessage with ObjCMethodCall and friends. Previously, the CallEvent subclass ObjCMessageInvocation was just a wrapper around the existing ObjCMessage abstraction (over message sends and property accesses). Now, we have abstract CallEvent ObjCMethodCall with subclasses ObjCMessageSend and ObjCPropertyAccess. In addition to removing yet another wrapper object, this should make it easy to add a ObjCSubscriptAccess call event soon. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159558 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../StaticAnalyzer/Core/PathSensitive/Calls.h | 93 ++++++++++++++----- .../Core/PathSensitive/ExprEngine.h | 6 +- .../Core/PathSensitive/ObjCMessage.h | 2 +- .../Checkers/CallAndMessageChecker.cpp | 3 +- lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 14 +-- .../Checkers/ObjCSelfInitChecker.cpp | 8 +- .../Checkers/RetainCountChecker.cpp | 17 ++-- lib/StaticAnalyzer/Core/Calls.cpp | 15 +-- lib/StaticAnalyzer/Core/ExprEngine.cpp | 22 +++-- lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 36 ++++--- 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(Call) || isa(Call))) + if (!(isa(Call) || isa(Call))) return false; // Check Objective-C messages by selector name. - if (const ObjCMessageInvocation *Msg = dyn_cast(Call)){ + if (const ObjCMethodCall *Msg = dyn_cast(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(Call); + case CE_ObjCMessage: + case CE_ObjCPropertyAccess: { + const ObjCMethodCall &Msg = cast(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(&CallOrMsg); + const ObjCMethodCall *MsgInvocation = dyn_cast(&CallOrMsg); if (MsgInvocation) { if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { if (const RefVal *T = state->get(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(S); bool evaluated = false; if (const PseudoObjectExpr *PO = - dyn_cast_or_null(PM.getParent(S))) { + dyn_cast_or_null(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(syntactic)) + syntactic = BO->getLHS(); + if (const ObjCPropertyRefExpr *PR = dyn_cast(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(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(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 (). + // 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(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()); } -- 2.40.0