diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-07-02 19:27:56 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-07-02 19:27:56 +0000 |
commit | 6bad4905d73ef9634e23709ba79747e83b27881c (patch) | |
tree | 7a2fd03e588399deb2060f19255a4d926c804e11 /clang/lib/StaticAnalyzer/Core | |
parent | 7ab0182e33eee81dfc884e9cf95863bcaf30bab0 (diff) | |
download | bcm5719-llvm-6bad4905d73ef9634e23709ba79747e83b27881c.tar.gz bcm5719-llvm-6bad4905d73ef9634e23709ba79747e83b27881c.zip |
[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.
llvm-svn: 159558
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/Calls.cpp | 15 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 22 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 36 |
3 files changed, 38 insertions, 35 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/Calls.cpp b/clang/lib/StaticAnalyzer/Core/Calls.cpp index 510f8340a2c..bdd4508ceaf 100644 --- a/clang/lib/StaticAnalyzer/Core/Calls.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 255d8701865..141c5bbf030 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index d35d999b5e9..86630a8c028 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/clang/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()); } |