CE_BEG_SIMPLE_CALLS = CE_Function,
CE_END_SIMPLE_CALLS = CE_Block,
CE_CXXConstructor,
+ CE_CXXDestructor,
CE_CXXAllocator,
CE_BEG_FUNCTION_CALLS = CE_Function,
CE_END_FUNCTION_CALLS = CE_CXXAllocator,
}
/// \brief Returns an appropriate ProgramPoint for this call.
- ProgramPoint getProgramPoint(bool IsPreVisit,
+ ProgramPoint getProgramPoint(bool IsPreVisit = false,
const ProgramPointTag *Tag = 0) const;
/// \brief Returns a new state with all argument regions invalidated.
}
};
+/// \brief Represents an implicit call to a C++ destructor.
+///
+/// This can occur at the end of a scope (for automatic objects), at the end
+/// of a full-expression (for temporaries), or as part of a delete.
+class CXXDestructorCall : public AnyFunctionCall {
+ const CXXDestructorDecl *DD;
+ const MemRegion *Target;
+ SourceLocation Loc;
+
+protected:
+ void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+ CXXDestructorCall(const CXXDestructorDecl *dd, const Stmt *Trigger,
+ const MemRegion *target, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(St, LCtx, CE_CXXDestructor), DD(dd), Target(target),
+ Loc(Trigger->getLocEnd()) {}
+
+ const Expr *getOriginExpr() const { return 0; }
+ SourceRange getSourceRange() const { return Loc; }
+
+ const CXXDestructorDecl *getDecl() const { return DD; }
+ unsigned getNumArgs() const { return 0; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXDestructor;
+ }
+};
+
/// \brief Represents the memory allocation call in a C++ new-expression.
///
/// This is a call to "operator new".
case CE_CXXMemberOperator:
case CE_Block:
case CE_CXXConstructor:
+ case CE_CXXDestructor:
case CE_CXXAllocator:
// FIXME: These calls are currently unsupported.
return getPersistentStopSummary();
}
+void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ if (Target)
+ Regions.push_back(Target);
+}
+
+
CallEvent::param_iterator ObjCMethodCall::param_begin() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
- if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
- return;
+ CXXDestructorCall Call(DD, S, Dest, Pred->getState(),
+ Pred->getLocationContext());
- // Create the context for 'this' region.
- const StackFrameContext *SFC =
- AnalysisDeclContexts.getContext(DD)->
- getStackFrame(Pred->getLocationContext(), S,
- currentBuilderContext->getBlock(), currentStmtIdx);
+ ExplodedNodeSet DstPreCall;
+ getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
+ Call, *this);
- CallEnter PP(S, SFC, Pred->getLocationContext());
- ProgramStateRef state = Pred->getState();
- state = state->bindLoc(svalBuilder.getCXXThis(DD->getParent(), SFC),
- loc::MemRegionVal(Dest));
- Bldr.generateNode(PP, Pred, state);
+ ExplodedNodeSet DstInvalidated;
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ defaultEvalCall(DstInvalidated, *I, Call);
+
+ ExplodedNodeSet DstPostCall;
+ getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
+ Call, *this);
}
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// enterStackFrame as well.
return false;
case CE_CXXConstructor:
- // Do not inline constructors until we can model destructors.
+ case CE_CXXDestructor:
+ // Do not inline constructors until we can really model destructors.
// This is unfortunate, but basically necessary for smart pointers and such.
return false;
case CE_CXXAllocator:
return;
// If we can't inline it, handle the return value and invalidate the regions.
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
// Invalidate any regions touched by the call.
unsigned Count = currentBuilderContext->getCurrentBlockCount();
state = Call.invalidateRegions(Count, state);
// Conjure a symbol value to use as the result.
- assert(Call.getOriginExpr() && "Must have an expression to bind the result");
- QualType ResultTy = Call.getResultType();
- SValBuilder &SVB = getSValBuilder();
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal RetVal = SVB.getConjuredSymbolVal(0, Call.getOriginExpr(), LCtx,
- ResultTy, Count);
+ if (E) {
+ QualType ResultTy = Call.getResultType();
+ SValBuilder &SVB = getSValBuilder();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+
+ state = state->BindExpr(E, LCtx, RetVal);
+ }
// And make the result node.
- state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
- Bldr.generateNode(Call.getOriginExpr(), Pred, state);
+ Bldr.generateNode(Call.getProgramPoint(), state, Pred);
}
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,