/// \brief Returns the result type, adjusted for references.
QualType getResultType() const;
- /// \brief Returns the value of the implicit 'this' object, or UndefinedVal if
- /// this is not a C++ member function call.
- virtual SVal getCXXThisVal() const {
- return UndefinedVal();
- }
-
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
ProgramStateRef invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig = 0) const;
+ typedef std::pair<Loc, SVal> FrameBindingTy;
+ typedef SmallVectorImpl<FrameBindingTy> BindingsTy;
+
+ /// Populates the given SmallVector with the bindings in the callee's stack
+ /// frame at the start of this call.
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const = 0;
+
/// Returns a copy of this CallEvent, but using the given state.
template <typename T>
CallEventRef<T> cloneWithState(ProgramStateRef NewState) const;
/// If the call has no accessible declaration (or definition, if
/// \p UseDefinitionParams is set), \c param_begin() will be equal to
/// \c param_end().
- virtual param_iterator param_begin(bool UseDefinitionParams = false) const =0;
+ virtual param_iterator param_begin() const =0;
/// \sa param_begin()
- virtual param_iterator param_end(bool UseDefinitionParams = false) const = 0;
+ virtual param_iterator param_end() const = 0;
typedef llvm::mapped_iterator<param_iterator, get_type_fun>
param_type_iterator;
virtual bool argumentsMayEscape() const;
- virtual param_iterator param_begin(bool UseDefinitionParams = false) const;
- virtual param_iterator param_end(bool UseDefinitionParams = false) const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
+ virtual param_iterator param_begin() const;
+ virtual param_iterator param_end() const;
static bool classof(const CallEvent *CA) {
return CA->getKind() >= CE_BEG_FUNCTION_CALLS &&
CXXInstanceCall(const CXXInstanceCall &Other) : SimpleCall(Other) {}
public:
+ /// \brief Returns the value of the implicit 'this' object.
+ virtual SVal getCXXThisVal() const = 0;
+
virtual const Decl *getRuntimeDefinition() const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
static bool classof(const CallEvent *CA) {
return CA->getKind() >= CE_BEG_CXX_INSTANCE_CALLS &&
CA->getKind() <= CE_END_CXX_INSTANCE_CALLS;
return getBlockDecl();
}
- virtual param_iterator param_begin(bool UseDefinitionParams = false) const;
- virtual param_iterator param_end(bool UseDefinitionParams = false) const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
+ virtual param_iterator param_begin() const;
+ virtual param_iterator param_end() const;
virtual Kind getKind() const { return CE_Block; }
return getOriginExpr()->getArg(Index);
}
+ /// \brief Returns the value of the implicit 'this' object.
virtual SVal getCXXThisVal() const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
virtual Kind getKind() const { return CE_CXXConstructor; }
static bool classof(const CallEvent *CA) {
virtual SourceRange getSourceRange() const { return Location; }
virtual unsigned getNumArgs() const { return 0; }
+ /// \brief Returns the value of the implicit 'this' object.
virtual SVal getCXXThisVal() const;
+
virtual const Decl *getRuntimeDefinition() const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
virtual Kind getKind() const { return CE_CXXDestructor; }
static bool classof(const CallEvent *CA) {
llvm_unreachable("Unknown message kind");
}
- // TODO: We might want to only compute this once (or change the API for
- // getting the parameters). Currently, this gets called 3 times during
- // inlining.
virtual const Decl *getRuntimeDefinition() const;
- virtual param_iterator param_begin(bool UseDefinitionParams = false) const;
- virtual param_iterator param_end(bool UseDefinitionParams = false) const;
+ virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const;
+
+ virtual param_iterator param_begin() const;
+ virtual param_iterator param_end() const;
virtual Kind getKind() const { return CE_ObjCMessage; }
|| isa<CXXConstructExpr>(S);
}
+static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
+ CallEvent::BindingsTy &Bindings,
+ SValBuilder &SVB,
+ const CallEvent &Call,
+ CallEvent::param_iterator I,
+ CallEvent::param_iterator E) {
+ MemRegionManager &MRMgr = SVB.getRegionManager();
-CallEvent::param_iterator
-AnyFunctionCall::param_begin(bool UseDefinitionParams) const {
- const Decl *D = UseDefinitionParams ? getRuntimeDefinition()
- : getDecl();
+ unsigned Idx = 0;
+ for (; I != E; ++I, ++Idx) {
+ const ParmVarDecl *ParamDecl = *I;
+ assert(ParamDecl && "Formal parameter has no decl?");
+
+ SVal ArgVal = Call.getArgSVal(Idx);
+ if (!ArgVal.isUnknown()) {
+ Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx));
+ Bindings.push_back(std::make_pair(ParamLoc, ArgVal));
+ }
+ }
+
+ // FIXME: Variadic arguments are not handled at all right now.
+}
+
+
+CallEvent::param_iterator AnyFunctionCall::param_begin() const {
+ const FunctionDecl *D = getDecl();
if (!D)
return 0;
- return cast<FunctionDecl>(D)->param_begin();
+ return D->param_begin();
}
-CallEvent::param_iterator
-AnyFunctionCall::param_end(bool UseDefinitionParams) const {
- const Decl *D = UseDefinitionParams ? getRuntimeDefinition()
- : getDecl();
+CallEvent::param_iterator AnyFunctionCall::param_end() const {
+ const FunctionDecl *D = getDecl();
if (!D)
return 0;
- return cast<FunctionDecl>(D)->param_end();
+ return D->param_end();
+}
+
+void AnyFunctionCall::getInitialStackFrameContents(
+ const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ const FunctionDecl *D = cast<FunctionDecl>(CalleeCtx->getDecl());
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
+ D->param_begin(), D->param_end());
}
QualType AnyFunctionCall::getDeclaredResultType() const {
return 0;
}
+void CXXInstanceCall::getInitialStackFrameContents(
+ const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
+
+ SVal ThisVal = getCXXThisVal();
+ if (!ThisVal.isUnknown()) {
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+ Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
+ Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
+ }
+}
+
+
SVal CXXMemberCall::getCXXThisVal() const {
const Expr *Base = getOriginExpr()->getImplicitObjectArgument();
return dyn_cast_or_null<BlockDataRegion>(DataReg);
}
-CallEvent::param_iterator
-BlockCall::param_begin(bool UseDefinitionParams) const {
- // Blocks don't have distinct declarations and definitions.
- (void)UseDefinitionParams;
-
+CallEvent::param_iterator BlockCall::param_begin() const {
const BlockDecl *D = getBlockDecl();
if (!D)
return 0;
return D->param_begin();
}
-CallEvent::param_iterator
-BlockCall::param_end(bool UseDefinitionParams) const {
- // Blocks don't have distinct declarations and definitions.
- (void)UseDefinitionParams;
-
+CallEvent::param_iterator BlockCall::param_end() const {
const BlockDecl *D = getBlockDecl();
if (!D)
return 0;
Regions.push_back(R);
}
+void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ const BlockDecl *D = cast<BlockDecl>(CalleeCtx->getDecl());
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
+ D->param_begin(), D->param_end());
+}
+
+
QualType BlockCall::getDeclaredResultType() const {
const BlockDataRegion *BR = getBlockRegion();
if (!BR)
Regions.push_back(static_cast<const MemRegion *>(Data));
}
+void CXXConstructorCall::getInitialStackFrameContents(
+ const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
+
+ SVal ThisVal = getCXXThisVal();
+ if (!ThisVal.isUnknown()) {
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+ Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
+ Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
+ }
+}
+
+
SVal CXXDestructorCall::getCXXThisVal() const {
if (Data)
return 0;
}
+void CXXDestructorCall::getInitialStackFrameContents(
+ const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
-CallEvent::param_iterator
-ObjCMethodCall::param_begin(bool UseDefinitionParams) const {
- const Decl *D = UseDefinitionParams ? getRuntimeDefinition()
- : getDecl();
+ SVal ThisVal = getCXXThisVal();
+ if (!ThisVal.isUnknown()) {
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+ Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
+ Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
+ }
+}
+
+
+CallEvent::param_iterator ObjCMethodCall::param_begin() const {
+ const ObjCMethodDecl *D = getDecl();
if (!D)
return 0;
- return cast<ObjCMethodDecl>(D)->param_begin();
+ return D->param_begin();
}
-CallEvent::param_iterator
-ObjCMethodCall::param_end(bool UseDefinitionParams) const {
- const Decl *D = UseDefinitionParams ? getRuntimeDefinition()
- : getDecl();
+CallEvent::param_iterator ObjCMethodCall::param_end() const {
+ const ObjCMethodDecl *D = getDecl();
if (!D)
return 0;
- return cast<ObjCMethodDecl>(D)->param_end();
+ return D->param_end();
}
void
return 0;
}
+void ObjCMethodCall::getInitialStackFrameContents(
+ const StackFrameContext *CalleeCtx,
+ BindingsTy &Bindings) const {
+ const ObjCMethodDecl *D = cast<ObjCMethodDecl>(CalleeCtx->getDecl());
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
+ D->param_begin(), D->param_end());
+
+ SVal SelfVal = getReceiverSVal();
+ if (!SelfVal.isUnknown()) {
+ const VarDecl *SelfD = CalleeCtx->getAnalysisDeclContext()->getSelfDecl();
+ MemRegionManager &MRMgr = SVB.getRegionManager();
+ Loc SelfLoc = SVB.makeLoc(MRMgr.getVarRegion(SelfD, CalleeCtx));
+ Bindings.push_back(std::make_pair(SelfLoc, SelfVal));
+ }
+}
+
CallEventRef<SimpleCall>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
const LocationContext *ParentOfCallee = 0;
+ // FIXME: Refactor this check into a hypothetical CallEvent::canInline.
switch (Call.getKind()) {
case CE_Function:
case CE_CXXMember:
case CE_CXXMemberOperator:
// These are always at least possible to inline.
break;
- case CE_CXXConstructor:
- case CE_CXXDestructor: {
+ case CE_CXXConstructor: {
// Only inline constructors and destructors if we built the CFGs for them
// properly.
const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
!ADC->getCFGBuildOptions().AddInitializers)
return false;
+ const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
+
// FIXME: We don't handle constructors or destructors for arrays properly.
- const MemRegion *Target = Call.getCXXThisVal().getAsRegion();
+ const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion();
if (Target && isa<ElementRegion>(Target))
return false;
// FIXME: This is a hack. We don't handle temporary destructors
// right now, so we shouldn't inline their constructors.
- if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
- const CXXConstructExpr *CtorExpr = Ctor->getOriginExpr();
- if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
- if (!Target || !isa<DeclRegion>(Target))
- return false;
- }
+ const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
+ if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ if (!Target || !isa<DeclRegion>(Target))
+ return false;
+
+ break;
+ }
+ case CE_CXXDestructor: {
+ // Only inline constructors and destructors if we built the CFGs for them
+ // properly.
+ const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
+ if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
+ !ADC->getCFGBuildOptions().AddInitializers)
+ return false;
+
+ const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
+
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return false;
+
break;
}
case CE_CXXAllocator:
const StackFrameContext *LCtx) {
StoreRef Store = StoreRef(OldStore, *this);
- unsigned Idx = 0;
- for (CallEvent::param_iterator I = Call.param_begin(/*UseDefinition=*/true),
- E = Call.param_end(/*UseDefinition=*/true);
- I != E; ++I, ++Idx) {
- const ParmVarDecl *Decl = *I;
- assert(Decl && "Formal parameter has no decl?");
-
- SVal ArgVal = Call.getArgSVal(Idx);
- if (!ArgVal.isUnknown()) {
- Store = Bind(Store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(Decl, LCtx)),
- ArgVal);
- }
- }
+ SmallVector<CallEvent::FrameBindingTy, 16> InitialBindings;
+ Call.getInitialStackFrameContents(LCtx, InitialBindings);
- // FIXME: We will eventually want to generalize this to handle other non-
- // parameter arguments besides 'this' (such as 'self' for ObjC methods).
- SVal ThisVal = Call.getCXXThisVal();
- if (isa<DefinedSVal>(ThisVal)) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(Call.getDecl());
- loc::MemRegionVal ThisRegion = svalBuilder.getCXXThis(MD, LCtx);
- Store = Bind(Store.getStore(), ThisRegion, ThisVal);
+ for (CallEvent::BindingsTy::iterator I = InitialBindings.begin(),
+ E = InitialBindings.end();
+ I != E; ++I) {
+ Store = Bind(Store.getStore(), I->first, I->second);
}
- if (const ObjCMethodCall *MCall = dyn_cast<ObjCMethodCall>(&Call)) {
- SVal SelfVal = MCall->getReceiverSVal();
- const VarDecl *SelfDecl = LCtx->getAnalysisDeclContext()->getSelfDecl();
- Store = Bind(Store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(SelfDecl, LCtx)),
- SelfVal);
- }
return Store;
}