[cfe-commits] r161809 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/CheckerManager.h include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/CallEvent.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Jordan Rose
jordan_rose at apple.com
Mon Aug 13 16:46:05 PDT 2012
Author: jrose
Date: Mon Aug 13 18:46:05 2012
New Revision: 161809
URL: http://llvm.org/viewvc/llvm-project?rev=161809&view=rev
Log:
[analyzer] Reduce code duplication: make CXXDestructorCall a CXXInstanceCall.
While there is now some duplication between SimpleCall and the CXXInstanceCall
sub-hierarchy, this is much better than copy-and-pasting the devirtualization
logic shared by both instance methods and destructors.
An unfortunate side effect is that there is no longer a single CallEvent type
that corresponds to "calls written as CallExprs". For the most part this is a
good thing, but the checker callback eval::Call still takes a CallExpr rather
than a CallEvent (since we're not sure if we want to allow checkers to
evaluate other kinds of calls). A mistake here will be caught by a cast<> in
CheckerManager::runCheckersForEvalCall.
No functionality change.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Mon Aug 13 18:46:05 2012
@@ -319,9 +319,11 @@
SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
+ ///
+ /// Warning: Currently, the CallEvent MUST come from a CallExpr!
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const SimpleCall &CE, ExprEngine &Eng);
+ const CallEvent &CE, ExprEngine &Eng);
/// \brief Run checkers for the entire Translation Unit.
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Mon Aug 13 18:46:05 2012
@@ -32,15 +32,15 @@
enum CallEventKind {
CE_Function,
- CE_CXXMember,
- CE_CXXMemberOperator,
- CE_BEG_CXX_INSTANCE_CALLS = CE_CXXMember,
- CE_END_CXX_INSTANCE_CALLS = CE_CXXMemberOperator,
CE_Block,
CE_BEG_SIMPLE_CALLS = CE_Function,
CE_END_SIMPLE_CALLS = CE_Block,
- CE_CXXConstructor,
+ CE_CXXMember,
+ CE_CXXMemberOperator,
CE_CXXDestructor,
+ CE_BEG_CXX_INSTANCE_CALLS = CE_CXXMember,
+ CE_END_CXX_INSTANCE_CALLS = CE_CXXDestructor,
+ CE_CXXConstructor,
CE_CXXAllocator,
CE_BEG_FUNCTION_CALLS = CE_Function,
CE_END_FUNCTION_CALLS = CE_CXXAllocator,
@@ -377,7 +377,7 @@
}
};
-/// \brief Represents a call to a written as a CallExpr.
+/// \brief Represents a call to a non-C++ function, written as a CallExpr.
class SimpleCall : public AnyFunctionCall {
protected:
SimpleCall(const CallExpr *CE, ProgramStateRef St,
@@ -426,24 +426,80 @@
}
};
+/// \brief Represents a call to a block.
+///
+/// Example: <tt>^{ /* ... */ }()</tt>
+class BlockCall : public SimpleCall {
+ friend class CallEventManager;
+
+protected:
+ BlockCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : SimpleCall(CE, St, LCtx) {}
+
+ BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
+
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+ virtual QualType getDeclaredResultType() const;
+
+public:
+ /// \brief Returns the region associated with this instance of the block.
+ ///
+ /// This may be NULL if the block's origin is unknown.
+ const BlockDataRegion *getBlockRegion() const;
+
+ /// \brief Gets the declaration of the block.
+ ///
+ /// This is not an override of getDecl() because AnyFunctionCall has already
+ /// assumed that it's a FunctionDecl.
+ const BlockDecl *getBlockDecl() const {
+ const BlockDataRegion *BR = getBlockRegion();
+ if (!BR)
+ return 0;
+ return BR->getDecl();
+ }
+
+ virtual RuntimeDefinition getRuntimeDefinition() const {
+ return RuntimeDefinition(getBlockDecl());
+ }
+
+ 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; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_Block;
+ }
+};
+
/// \brief Represents a non-static C++ member function call, no matter how
/// it is written.
-class CXXInstanceCall : public SimpleCall {
+class CXXInstanceCall : public AnyFunctionCall {
protected:
virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : SimpleCall(CE, St, LCtx) {}
+ : AnyFunctionCall(CE, St, LCtx) {}
+ CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(D, St, LCtx) {}
+
- CXXInstanceCall(const CXXInstanceCall &Other) : SimpleCall(Other) {}
+ CXXInstanceCall(const CXXInstanceCall &Other) : AnyFunctionCall(Other) {}
public:
/// \brief Returns the expression representing the implicit 'this' object.
- virtual const Expr *getCXXThisExpr() const = 0;
+ virtual const Expr *getCXXThisExpr() const { return 0; }
/// \brief Returns the value of the implicit 'this' object.
- SVal getCXXThisVal() const {
+ virtual SVal getCXXThisVal() const {
const Expr *Base = getCXXThisExpr();
// FIXME: This doesn't handle an overloaded ->* operator.
if (!Base)
@@ -451,6 +507,8 @@
return getSVal(Base);
}
+ virtual const FunctionDecl *getDecl() const;
+
virtual RuntimeDefinition getRuntimeDefinition() const;
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -478,7 +536,17 @@
public:
virtual const CXXMemberCallExpr *getOriginExpr() const {
- return cast<CXXMemberCallExpr>(SimpleCall::getOriginExpr());
+ return cast<CXXMemberCallExpr>(CXXInstanceCall::getOriginExpr());
+ }
+
+ virtual unsigned getNumArgs() const {
+ if (const CallExpr *CE = getOriginExpr())
+ return CE->getNumArgs();
+ return 0;
+ }
+
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index);
}
virtual const Expr *getCXXThisExpr() const;
@@ -510,7 +578,7 @@
public:
virtual const CXXOperatorCallExpr *getOriginExpr() const {
- return cast<CXXOperatorCallExpr>(SimpleCall::getOriginExpr());
+ return cast<CXXOperatorCallExpr>(CXXInstanceCall::getOriginExpr());
}
virtual unsigned getNumArgs() const {
@@ -529,55 +597,43 @@
}
};
-/// \brief Represents a call to a block.
+/// \brief Represents an implicit call to a C++ destructor.
///
-/// Example: <tt>^{ /* ... */ }()</tt>
-class BlockCall : public SimpleCall {
+/// 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 CXXInstanceCall {
friend class CallEventManager;
protected:
- BlockCall(const CallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : SimpleCall(CE, St, LCtx) {}
-
- BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
-
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
-
- virtual QualType getDeclaredResultType() const;
-
-public:
- /// \brief Returns the region associated with this instance of the block.
- ///
- /// This may be NULL if the block's origin is unknown.
- const BlockDataRegion *getBlockRegion() const;
-
- /// \brief Gets the declaration of the block.
+ /// Creates an implicit destructor.
///
- /// This is not an override of getDecl() because AnyFunctionCall has already
- /// assumed that it's a FunctionDecl.
- const BlockDecl *getBlockDecl() const {
- const BlockDataRegion *BR = getBlockRegion();
- if (!BR)
- return 0;
- return BR->getDecl();
+ /// \param DD The destructor that will be called.
+ /// \param Trigger The statement whose completion causes this destructor call.
+ /// \param Target The object region to be destructed.
+ /// \param St The path-sensitive state at this point in the program.
+ /// \param LCtx The location context at this point in the program.
+ CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+ const MemRegion *Target, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(DD, St, LCtx) {
+ Data = Target;
+ Location = Trigger->getLocEnd();
}
- virtual RuntimeDefinition getRuntimeDefinition() const {
- return RuntimeDefinition(getBlockDecl());
- }
+ CXXDestructorCall(const CXXDestructorCall &Other) : CXXInstanceCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
- virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
- BindingsTy &Bindings) const;
+public:
+ virtual SourceRange getSourceRange() const { return Location; }
+ virtual unsigned getNumArgs() const { return 0; }
- virtual param_iterator param_begin() const;
- virtual param_iterator param_end() const;
+ /// \brief Returns the value of the implicit 'this' object.
+ virtual SVal getCXXThisVal() const;
- virtual Kind getKind() const { return CE_Block; }
+ virtual Kind getKind() const { return CE_CXXDestructor; }
static bool classof(const CallEvent *CA) {
- return CA->getKind() == CE_Block;
+ return CA->getKind() == CE_CXXDestructor;
}
};
@@ -622,7 +678,7 @@
}
/// \brief Returns the value of the implicit 'this' object.
- virtual SVal getCXXThisVal() const;
+ SVal getCXXThisVal() const;
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const;
@@ -634,53 +690,6 @@
}
};
-/// \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 {
- friend class CallEventManager;
-
-protected:
- /// Creates an implicit destructor.
- ///
- /// \param DD The destructor that will be called.
- /// \param Trigger The statement whose completion causes this destructor call.
- /// \param Target The object region to be destructed.
- /// \param St The path-sensitive state at this point in the program.
- /// \param LCtx The location context at this point in the program.
- CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
- const MemRegion *Target, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(DD, St, LCtx) {
- Data = Target;
- Location = Trigger->getLocEnd();
- }
-
- CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
-
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
-
-public:
- 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 RuntimeDefinition getRuntimeDefinition() const;
-
- virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
- BindingsTy &Bindings) const;
-
- virtual Kind getKind() const { return CE_CXXDestructor; }
-
- 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".
@@ -874,7 +883,7 @@
getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
- CallEventRef<SimpleCall>
+ CallEventRef<>
getSimpleCall(const CallExpr *E, ProgramStateRef State,
const LocationContext *LCtx);
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Aug 13 18:46:05 2012
@@ -463,8 +463,10 @@
const LocationContext *LCtx,
ProgramStateRef State);
+ /// Evaluate a call, running pre- and post-call checks and allowing checkers
+ /// to be responsible for handling the evaluation of the call itself.
void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
- const SimpleCall &Call);
+ const CallEvent &Call);
/// \brief Default implementation of call evaluation.
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Aug 13 18:46:05 2012
@@ -355,6 +355,18 @@
}
+const FunctionDecl *CXXInstanceCall::getDecl() const {
+ const CallExpr *CE = cast_or_null<CallExpr>(getOriginExpr());
+ if (!CE)
+ return AnyFunctionCall::getDecl();
+
+ const FunctionDecl *D = CE->getDirectCallee();
+ if (D)
+ return D;
+
+ return getSVal(CE->getCallee()).getAsFunctionDecl();
+}
+
void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const {
if (const MemRegion *R = getCXXThisVal().getAsRegion())
Regions.push_back(R);
@@ -389,7 +401,7 @@
const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
if (!MD->isVirtual())
- return SimpleCall::getRuntimeDefinition();
+ return AnyFunctionCall::getRuntimeDefinition();
// If the method is virtual, see if we can find the actual implementation
// based on context-sensitivity.
@@ -527,46 +539,6 @@
return UnknownVal();
}
-void CXXDestructorCall::getExtraInvalidatedRegions(RegionList &Regions) const {
- if (Data)
- Regions.push_back(static_cast<const MemRegion *>(Data));
-}
-
-RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
- const Decl *D = AnyFunctionCall::getRuntimeDefinition().getDecl();
- if (!D)
- return RuntimeDefinition();
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
- if (!MD->isVirtual())
- return RuntimeDefinition(MD);
-
- // If the method is virtual, see if we can find the actual implementation
- // based on context-sensitivity.
- // FIXME: Virtual method calls behave differently when an object is being
- // constructed or destructed. It's not as simple as "no devirtualization"
- // because a /partially/ constructed object can be referred to through a
- // base pointer. We'll eventually want to use DynamicTypeInfo here.
- if (const CXXMethodDecl *Devirtualized = devirtualize(MD, getCXXThisVal()))
- return RuntimeDefinition(Devirtualized);
-
- return RuntimeDefinition();
-}
-
-void CXXDestructorCall::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));
- }
-}
-
CallEvent::param_iterator ObjCMethodCall::param_begin() const {
const ObjCMethodDecl *D = getDecl();
@@ -805,7 +777,7 @@
}
}
-CallEventRef<SimpleCall>
+CallEventRef<>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
const LocationContext *LCtx) {
if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE))
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Aug 13 18:46:05 2012
@@ -504,9 +504,9 @@
/// Only one checker will evaluate the call.
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const SimpleCall &Call,
+ const CallEvent &Call,
ExprEngine &Eng) {
- const CallExpr *CE = Call.getOriginExpr();
+ const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
for (ExplodedNodeSet::iterator
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=161809&r1=161808&r2=161809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Aug 13 18:46:05 2012
@@ -445,7 +445,7 @@
// Get the call in its initial state. We use this as a template to perform
// all the checks.
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<SimpleCall> CallTemplate
+ CallEventRef<> CallTemplate
= CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
// Evaluate the function call. We try each of the checkers
@@ -465,7 +465,7 @@
}
void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
- const SimpleCall &Call) {
+ const CallEvent &Call) {
// WARNING: At this time, the state attached to 'Call' may be older than the
// state in 'Pred'. This is a minor optimization since CheckerManager will
// use an updated CallEvent instance when calling checkers, but if 'Call' is
More information about the cfe-commits
mailing list