aboutsummaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
commit56d91b49b13fe55c918afbda19f6165b5fbff87a (patch)
tree9abb1a658a297776086f4e0dfa6ca533de02104e /include/clang/StaticAnalyzer
parent41e20f564abdb05101d6b2b29c59459a966c22cc (diff)
downloadsrc-56d91b49b13fe55c918afbda19f6165b5fbff87a.tar.gz
src-56d91b49b13fe55c918afbda19f6165b5fbff87a.zip
Notes
Diffstat (limited to 'include/clang/StaticAnalyzer')
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h20
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h36
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h65
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h71
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h106
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h962
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h94
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h7
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h86
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h293
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h102
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h25
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h42
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h70
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h14
22 files changed, 1516 insertions, 568 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 2b699a85f8ef..5ee52cc61589 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -101,20 +101,27 @@ protected:
/// Used for clients to tell if the report's configuration has changed
/// since the last time they checked.
unsigned ConfigurationChangeToken;
+
+ /// When set, this flag disables all callstack pruning from a diagnostic
+ /// path. This is useful for some reports that want maximum fidelty
+ /// when reporting an issue.
+ bool DoNotPrunePath;
public:
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
: BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode),
- ConfigurationChangeToken(0) {}
+ ConfigurationChangeToken(0), DoNotPrunePath(false) {}
BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
const ExplodedNode *errornode)
: BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode), ConfigurationChangeToken(0) {}
+ ErrorNode(errornode), ConfigurationChangeToken(0),
+ DoNotPrunePath(false) {}
BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
: BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0),
- ConfigurationChangeToken(0) {}
+ ConfigurationChangeToken(0),
+ DoNotPrunePath(false) {}
/// \brief Create a BugReport with a custom uniqueing location.
///
@@ -142,6 +149,13 @@ public:
return ShortDescription.empty() ? Description : ShortDescription;
}
+ /// Indicates whether or not any path pruning should take place
+ /// when generating a PathDiagnostic from this BugReport.
+ bool shouldPrunePath() const { return !DoNotPrunePath; }
+
+ /// Disable all path pruning when generating a PathDiagnostic.
+ void disablePathPruning() { DoNotPrunePath = true; }
+
void markInteresting(SymbolRef sym);
void markInteresting(const MemRegion *R);
void markInteresting(SVal V);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 7e665ceda54b..f53c15f117c9 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -226,13 +226,11 @@ public:
namespace bugreporter {
-BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S,
- BugReport *R);
+void addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S,
+ BugReport *R);
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
-const Stmt *GetCalleeExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
} // end namespace clang
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 5a8a1c78ca7d..2e7abfa5cc3b 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -148,6 +148,15 @@ public:
assert(Range.isValid());
}
+ /// Create a location at an explicit offset in the source.
+ ///
+ /// This should only be used if there are no more appropriate constructors.
+ PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
+ : K(SingleLocK), S(0), D(0), SM(&sm), Loc(loc, sm), Range(genRange()) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
+
/// Create a location corresponding to the given declaration.
static PathDiagnosticLocation create(const Decl *D,
const SourceManager &SM) {
@@ -163,6 +172,14 @@ public:
const SourceManager &SM,
const LocationOrAnalysisDeclContext LAC);
+ /// Create a location for the end of the statement.
+ ///
+ /// If the statement is a CompoundStatement, the location will point to the
+ /// closing brace instead of following it.
+ static PathDiagnosticLocation createEnd(const Stmt *S,
+ const SourceManager &SM,
+ const LocationOrAnalysisDeclContext LAC);
+
/// Create the location for the operator of the binary expression.
/// Assumes the statement has a valid location.
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
@@ -333,10 +350,17 @@ public:
};
-class PathPieces :
- public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
+class PathPieces : public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
+ void flattenTo(PathPieces &Primary, PathPieces &Current,
+ bool ShouldFlattenMacros) const;
public:
- ~PathPieces();
+ ~PathPieces();
+
+ PathPieces flatten(bool ShouldFlattenMacros) const {
+ PathPieces Result;
+ flattenTo(Result, Result, ShouldFlattenMacros);
+ return Result;
+ }
};
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
@@ -362,7 +386,7 @@ public:
/// \brief Interface for classes constructing Stack hints.
///
/// If a PathDiagnosticEvent occurs in a different frame than the final
-/// diagnostic the hints can be used to summarise the effect of the call.
+/// diagnostic the hints can be used to summarize the effect of the call.
class StackHintGenerator {
public:
virtual ~StackHintGenerator() = 0;
@@ -510,7 +534,7 @@ public:
}
static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
- const CallExit &CE,
+ const CallExitEnd &CE,
const SourceManager &SM);
static PathDiagnosticCallPiece *construct(PathPieces &pieces,
@@ -637,6 +661,8 @@ public:
void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
+
+ bool isWithinCall() const { return !pathStack.empty(); }
// PathDiagnostic();
PathDiagnostic(const Decl *DeclWithIssue,
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 76d8c15f75cb..3214d96c5398 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -122,7 +122,7 @@ public:
class PreObjCMessage {
template <typename CHECKER>
- static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+ static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
CheckerContext &C) {
((const CHECKER *)checker)->checkPreObjCMessage(msg, C);
}
@@ -137,7 +137,7 @@ public:
class PostObjCMessage {
template <typename CHECKER>
- static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+ static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
CheckerContext &C) {
((const CHECKER *)checker)->checkPostObjCMessage(msg, C);
}
@@ -150,6 +150,36 @@ public:
}
};
+class PreCall {
+ template <typename CHECKER>
+ static void _checkCall(void *checker, const CallEvent &msg,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkPreCall(msg, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForPreCall(
+ CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
+ }
+};
+
+class PostCall {
+ template <typename CHECKER>
+ static void _checkCall(void *checker, const CallEvent &msg,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkPostCall(msg, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForPostCall(
+ CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
+ }
+};
+
class Location {
template <typename CHECKER>
static void _checkLocation(void *checker,
@@ -266,7 +296,7 @@ class RegionChanges {
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call) {
+ const CallEvent *Call) {
return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
Explicits, Regions, Call);
}
@@ -372,16 +402,14 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck,
typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck,
typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck,
- typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck>
+ typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck,
+ typename CHECK19=check::_VoidCheck,typename CHECK20=check::_VoidCheck,
+ typename CHECK21=check::_VoidCheck,typename CHECK22=check::_VoidCheck,
+ typename CHECK23=check::_VoidCheck,typename CHECK24=check::_VoidCheck>
class Checker;
template <>
-class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck, check::_VoidCheck, check::_VoidCheck>
+class Checker<check::_VoidCheck>
: public CheckerBase
{
virtual void anchor();
@@ -393,19 +421,22 @@ template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4,
typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16,
- typename CHECK17,typename CHECK18>
+ typename CHECK17,typename CHECK18,typename CHECK19,typename CHECK20,
+ typename CHECK21,typename CHECK22,typename CHECK23,typename CHECK24>
class Checker
: public CHECK1,
- public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
- CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
- CHECK16,CHECK17,CHECK18> {
+ public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
+ CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
+ CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
+ CHECK20,CHECK21,CHECK22,CHECK23,CHECK24> {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
- Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
- CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
- CHECK16,CHECK17,CHECK18>::_register(checker, mgr);
+ Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
+ CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
+ CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
+ CHECK20,CHECK21,CHECK22,CHECK23,CHECK24>::_register(checker, mgr);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index d215f992e68e..e11b6d518a4e 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -33,7 +33,8 @@ namespace ento {
class AnalysisManager;
class BugReporter;
class CheckerContext;
- class ObjCMessage;
+ class SimpleCall;
+ class ObjCMethodCall;
class SVal;
class ExplodedNode;
class ExplodedNodeSet;
@@ -44,12 +45,6 @@ namespace ento {
class MemRegion;
class SymbolReaper;
-class GraphExpander {
-public:
- virtual ~GraphExpander();
- virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
-};
-
template <typename T> class CheckerFn;
template <typename RET, typename P1, typename P2, typename P3, typename P4,
@@ -207,7 +202,7 @@ public:
/// \brief Run checkers for pre-visiting obj-c messages.
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
ExprEngine &Eng) {
runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng);
}
@@ -215,16 +210,39 @@ public:
/// \brief Run checkers for post-visiting obj-c messages.
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg,
- ExprEngine &Eng) {
- runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
+ const ObjCMethodCall &msg,
+ ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng,
+ wasInlined);
}
/// \brief Run checkers for visiting obj-c messages.
void runCheckersForObjCMessage(bool isPreVisit,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg, ExprEngine &Eng);
+ const ObjCMethodCall &msg, ExprEngine &Eng,
+ bool wasInlined = false);
+
+ /// \brief Run checkers for pre-visiting obj-c messages.
+ void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+ const CallEvent &Call, ExprEngine &Eng) {
+ runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng);
+ }
+
+ /// \brief Run checkers for post-visiting obj-c messages.
+ void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+ const CallEvent &Call, ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng,
+ wasInlined);
+ }
+
+ /// \brief Run checkers for visiting obj-c messages.
+ void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const CallEvent &Call, ExprEngine &Eng,
+ bool wasInlined = false);
/// \brief Run checkers for load/store of a location.
void runCheckersForLocation(ExplodedNodeSet &Dst,
@@ -272,7 +290,8 @@ public:
void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SymbolReaper &SymReaper, const Stmt *S,
- ExprEngine &Eng);
+ ExprEngine &Eng,
+ ProgramPoint::Kind K);
/// \brief True if at least one checker wants to check region changes.
bool wantsRegionChangeUpdate(ProgramStateRef state);
@@ -286,24 +305,25 @@ public:
/// For example, in the case of a function call, these would be arguments.
/// \param Regions The transitive closure of accessible regions,
/// i.e. all regions that may have been touched by this change.
- /// \param The call expression wrapper if the regions are invalidated by a
- /// call.
- ProgramStateRef
+ /// \param Call The call expression wrapper if the regions are invalidated
+ /// by a call.
+ ProgramStateRef
runCheckersForRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call);
+ const CallEvent *Call);
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
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 CallExpr *CE, ExprEngine &Eng,
- GraphExpander *defaultEval = 0);
+ const CallEvent &CE, ExprEngine &Eng);
/// \brief Run checkers for the entire Translation Unit.
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
@@ -342,8 +362,11 @@ public:
typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc;
- typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
+ typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>
CheckObjCMessageFunc;
+
+ typedef CheckerFn<void (const CallEvent &, CheckerContext &)>
+ CheckCallFunc;
typedef CheckerFn<void (const SVal &location, bool isLoad,
const Stmt *S,
@@ -372,7 +395,7 @@ public:
const StoreManager::InvalidatedSymbols *symbols,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call)>
+ const CallEvent *Call)>
CheckRegionChangesFunc;
typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;
@@ -402,6 +425,9 @@ public:
void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
+ void _registerForPreCall(CheckCallFunc checkfn);
+ void _registerForPostCall(CheckCallFunc checkfn);
+
void _registerForLocation(CheckLocationFunc checkfn);
void _registerForBind(CheckBindFunc checkfn);
@@ -523,6 +549,9 @@ private:
std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
+ std::vector<CheckCallFunc> PreCallCheckers;
+ std::vector<CheckCallFunc> PostCallCheckers;
+
std::vector<CheckLocationFunc> LocationCheckers;
std::vector<CheckBindFunc> BindCheckers;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
new file mode 100644
index 000000000000..e1ff17b361aa
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -0,0 +1,106 @@
+//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CORE_APSINTTYPE_H
+#define LLVM_CLANG_SA_CORE_APSINTTYPE_H
+
+#include "llvm/ADT/APSInt.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief A record of the "type" of an APSInt, used for conversions.
+class APSIntType {
+ uint32_t BitWidth;
+ bool IsUnsigned;
+
+public:
+ APSIntType(uint32_t Width, bool Unsigned)
+ : BitWidth(Width), IsUnsigned(Unsigned) {}
+
+ /* implicit */ APSIntType(const llvm::APSInt &Value)
+ : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {}
+
+ uint32_t getBitWidth() const { return BitWidth; }
+ bool isUnsigned() const { return IsUnsigned; }
+
+ /// \brief Convert a given APSInt, in place, to match this type.
+ ///
+ /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives
+ /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF).
+ void apply(llvm::APSInt &Value) const {
+ // Note the order here. We extend first to preserve the sign, if this value
+ // is signed, /then/ match the signedness of the result type.
+ Value = Value.extOrTrunc(BitWidth);
+ Value.setIsUnsigned(IsUnsigned);
+ }
+
+ /// Convert and return a new APSInt with the given value, but this
+ /// type's bit width and signedness.
+ ///
+ /// \see apply
+ llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY {
+ llvm::APSInt Result(Value, Value.isUnsigned());
+ apply(Result);
+ return Result;
+ }
+
+ /// Returns an all-zero value for this type.
+ llvm::APSInt getZeroValue() const LLVM_READONLY {
+ return llvm::APSInt(BitWidth, IsUnsigned);
+ }
+
+ /// Returns the minimum value for this type.
+ llvm::APSInt getMinValue() const LLVM_READONLY {
+ return llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
+ }
+
+ /// Returns the maximum value for this type.
+ llvm::APSInt getMaxValue() const LLVM_READONLY {
+ return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
+ }
+
+ /// Used to classify whether a value is representable using this type.
+ ///
+ /// \see testInRange
+ enum RangeTestResultKind {
+ RTR_Below = -1, ///< Value is less than the minimum representable value.
+ RTR_Within = 0, ///< Value is representable using this type.
+ RTR_Above = 1 ///< Value is greater than the maximum representable value.
+ };
+
+ /// Tests whether a given value is losslessly representable using this type.
+ ///
+ /// Note that signedness conversions will be rejected, even with the same bit
+ /// pattern. For example, -1s8 is not in range for 'unsigned char' (u8).
+ RangeTestResultKind testInRange(const llvm::APSInt &Val) const LLVM_READONLY;
+
+ bool operator==(const APSIntType &Other) const {
+ return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
+ }
+
+ /// \brief Provide an ordering for finding a common conversion type.
+ ///
+ /// Unsigned integers are considered to be better conversion types than
+ /// signed integers of the same width.
+ bool operator<(const APSIntType &Other) const {
+ if (BitWidth < Other.BitWidth)
+ return true;
+ if (BitWidth > Other.BitWidth)
+ return false;
+ if (!IsUnsigned && Other.IsUnsigned)
+ return true;
+ return false;
+ }
+};
+
+} // end ento namespace
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index d01644ba0eb5..1cc53d4423da 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -41,8 +41,6 @@ class AnalysisManager : public BugReporterData {
CheckerManager *CheckerMgr;
- enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
-
/// \brief The maximum number of exploded nodes the analyzer will generate.
unsigned MaxNodes;
@@ -93,7 +91,7 @@ public:
bool vizdot, bool vizubi, AnalysisPurgeMode purge,
bool eager, bool trim,
bool useUnoptimizedCFG,
- bool addImplicitDtors, bool addInitializers,
+ bool addImplicitDtors,
bool eagerlyTrimEGraph,
AnalysisIPAMode ipa,
unsigned inlineMaxStack,
@@ -171,7 +169,7 @@ public:
bool shouldEagerlyAssume() const { return EagerlyAssume; }
- bool shouldInlineCall() const { return (IPAMode == Inlining); }
+ bool shouldInlineCall() const { return (IPAMode != None); }
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
@@ -190,10 +188,6 @@ public:
return AnaCtxMgr.getContext(D);
}
- AnalysisDeclContext *getAnalysisDeclContext(const Decl *D, idx::TranslationUnit *TU) {
- return AnaCtxMgr.getContext(D, TU);
- }
-
};
} // enAnaCtxMgrspace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 9a699f9b7c9c..b4a9de76f4d1 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -86,28 +87,30 @@ public:
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
+ /// Returns the type of the APSInt used to store values of the given QualType.
+ APSIntType getAPSIntType(QualType T) const {
+ assert(T->isIntegerType() || Loc::isLocType(T));
+ return APSIntType(Ctx.getTypeSize(T),
+ !T->isSignedIntegerOrEnumerationType());
+ }
+
/// Convert - Create a new persistent APSInt with the same value as 'From'
/// but with the bitwidth and signedness of 'To'.
const llvm::APSInt &Convert(const llvm::APSInt& To,
const llvm::APSInt& From) {
-
- if (To.isUnsigned() == From.isUnsigned() &&
- To.getBitWidth() == From.getBitWidth())
+ APSIntType TargetType(To);
+ if (TargetType == APSIntType(From))
return From;
- return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
+ return getValue(TargetType.convert(From));
}
const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
- assert(T->isIntegerType() || Loc::isLocType(T));
- unsigned bitwidth = Ctx.getTypeSize(T);
- bool isUnsigned
- = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
-
- if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
+ APSIntType TargetType = getAPSIntType(T);
+ if (TargetType == APSIntType(From))
return From;
- return getValue(From.getSExtValue(), bitwidth, isUnsigned);
+ return getValue(TargetType.convert(From));
}
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
@@ -116,25 +119,19 @@ public:
}
inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
- return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
+ return getValue(APSIntType(v).getMaxValue());
}
inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
- return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
+ return getValue(APSIntType(v).getMinValue());
}
inline const llvm::APSInt& getMaxValue(QualType T) {
- assert(T->isIntegerType() || Loc::isLocType(T));
- bool isUnsigned
- = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
- return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
+ return getValue(getAPSIntType(T).getMaxValue());
}
inline const llvm::APSInt& getMinValue(QualType T) {
- assert(T->isIntegerType() || Loc::isLocType(T));
- bool isUnsigned
- = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
- return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
+ return getValue(getAPSIntType(T).getMinValue());
}
inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
new file mode 100644
index 000000000000..47edfe9fca91
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -0,0 +1,962 @@
+//===- CallEvent.h - Wrapper for all function and method calls ----*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file defines CallEvent and its subclasses, which represent path-
+/// sensitive instances of different kinds of function and method calls
+/// (C, C++, and Objective-C).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
+#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace clang {
+class ProgramPoint;
+class ProgramPointTag;
+
+namespace ento {
+
+enum CallEventKind {
+ CE_Function,
+ CE_Block,
+ CE_BEG_SIMPLE_CALLS = CE_Function,
+ CE_END_SIMPLE_CALLS = CE_Block,
+ 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,
+ CE_ObjCMessage
+};
+
+class CallEvent;
+class CallEventManager;
+
+template<typename T = CallEvent>
+class CallEventRef : public IntrusiveRefCntPtr<const T> {
+public:
+ CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {}
+ CallEventRef(const CallEventRef &Orig) : IntrusiveRefCntPtr<const T>(Orig) {}
+
+ CallEventRef<T> cloneWithState(ProgramStateRef State) const {
+ return this->getPtr()->template cloneWithState<T>(State);
+ }
+
+ // Allow implicit conversions to a superclass type, since CallEventRef
+ // behaves like a pointer-to-const.
+ template <typename SuperT>
+ operator CallEventRef<SuperT> () const {
+ return this->getPtr();
+ }
+};
+
+/// \brief Defines the runtime definition of the called function.
+class RuntimeDefinition {
+ /// The Declaration of the function which will be called at runtime.
+ /// 0 if not available.
+ const Decl *D;
+
+ /// The region representing an object (ObjC/C++) on which the method is
+ /// called. With dynamic dispatch, the method definition depends on the
+ /// runtime type of this object. 0 when there is no dynamic dispatch.
+ const MemRegion *R;
+
+public:
+ RuntimeDefinition(): D(0), R(0) {}
+ RuntimeDefinition(const Decl *InD): D(InD), R(0) {}
+ RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
+ const Decl *getDecl() { return D; }
+ const MemRegion *getDispatchRegion() { return R; }
+ bool mayHaveOtherDefinitions() { return R != 0; }
+};
+
+/// \brief Represents an abstract call to a function or method along a
+/// particular path.
+///
+/// CallEvents are created through the factory methods of CallEventManager.
+///
+/// CallEvents should always be cheap to create and destroy. In order for
+/// CallEventManager to be able to re-use CallEvent-sized memory blocks,
+/// subclasses of CallEvent may not add any data members to the base class.
+/// Use the "Data" and "Location" fields instead.
+class CallEvent {
+public:
+ typedef CallEventKind Kind;
+
+private:
+ ProgramStateRef State;
+ const LocationContext *LCtx;
+ llvm::PointerUnion<const Expr *, const Decl *> Origin;
+
+ // DO NOT IMPLEMENT
+ CallEvent &operator=(const CallEvent &);
+
+protected:
+ // This is user data for subclasses.
+ const void *Data;
+
+ // This is user data for subclasses.
+ // This should come right before RefCount, so that the two fields can be
+ // packed together on LP64 platforms.
+ SourceLocation Location;
+
+private:
+ mutable unsigned RefCount;
+
+ template <typename T> friend struct llvm::IntrusiveRefCntPtrInfo;
+ void Retain() const { ++RefCount; }
+ void Release() const;
+
+protected:
+ friend class CallEventManager;
+
+ CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
+ : State(state), LCtx(lctx), Origin(E), RefCount(0) {}
+
+ CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
+ : State(state), LCtx(lctx), Origin(D), RefCount(0) {}
+
+ // DO NOT MAKE PUBLIC
+ CallEvent(const CallEvent &Original)
+ : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
+ Data(Original.Data), Location(Original.Location), RefCount(0) {}
+
+
+ ProgramStateRef getState() const {
+ return State;
+ }
+
+ const LocationContext *getLocationContext() const {
+ return LCtx;
+ }
+
+
+ /// Copies this CallEvent, with vtable intact, into a new block of memory.
+ virtual void cloneTo(void *Dest) const = 0;
+
+ /// \brief Get the value of arbitrary expressions at this point in the path.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
+
+ typedef SmallVectorImpl<const MemRegion *> RegionList;
+
+ /// \brief Used to specify non-argument regions that will be invalidated as a
+ /// result of this call.
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const {}
+
+ virtual QualType getDeclaredResultType() const = 0;
+
+public:
+ virtual ~CallEvent() {}
+
+ /// \brief Returns the kind of call this is.
+ virtual Kind getKind() const = 0;
+
+ /// \brief Returns the declaration of the function or method that will be
+ /// called. May be null.
+ virtual const Decl *getDecl() const {
+ return Origin.dyn_cast<const Decl *>();
+ }
+
+ /// \brief Returns the definition of the function or method that will be
+ /// called.
+ virtual RuntimeDefinition getRuntimeDefinition() const = 0;
+
+ /// \brief Returns the expression whose value will be the result of this call.
+ /// May be null.
+ const Expr *getOriginExpr() const {
+ return Origin.dyn_cast<const Expr *>();
+ }
+
+ /// \brief Returns the number of arguments (explicit and implicit).
+ ///
+ /// Note that this may be greater than the number of parameters in the
+ /// callee's declaration, and that it may include arguments not written in
+ /// the source.
+ virtual unsigned getNumArgs() const = 0;
+
+ /// \brief Returns true if the callee is known to be from a system header.
+ bool isInSystemHeader() const {
+ const Decl *D = getDecl();
+ if (!D)
+ return false;
+
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isValid()) {
+ const SourceManager &SM =
+ getState()->getStateManager().getContext().getSourceManager();
+ return SM.isInSystemHeader(D->getLocation());
+ }
+
+ // Special case for implicitly-declared global operator new/delete.
+ // These should be considered system functions.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal();
+
+ return false;
+ }
+
+ /// \brief Returns a source range for the entire call, suitable for
+ /// outputting in diagnostics.
+ virtual SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
+
+ /// \brief Returns the value of a given argument at the time of the call.
+ virtual SVal getArgSVal(unsigned Index) const;
+
+ /// \brief Returns the expression associated with a given argument.
+ /// May be null if this expression does not appear in the source.
+ virtual const Expr *getArgExpr(unsigned Index) const { return 0; }
+
+ /// \brief Returns the source range for errors associated with this argument.
+ ///
+ /// May be invalid if the argument is not written in the source.
+ virtual SourceRange getArgSourceRange(unsigned Index) const;
+
+ /// \brief Returns the result type, adjusted for references.
+ QualType getResultType() const;
+
+ /// \brief Returns true if any of the arguments appear to represent callbacks.
+ bool hasNonZeroCallbackArg() const;
+
+ /// \brief Returns true if any of the arguments are known to escape to long-
+ /// term storage, even if this method will not modify them.
+ // NOTE: The exact semantics of this are still being defined!
+ // We don't really want a list of hardcoded exceptions in the long run,
+ // but we don't want duplicated lists of known APIs in the short term either.
+ virtual bool argumentsMayEscape() const {
+ return hasNonZeroCallbackArg();
+ }
+
+ /// \brief Returns an appropriate ProgramPoint for this call.
+ ProgramPoint getProgramPoint(bool IsPreVisit = false,
+ const ProgramPointTag *Tag = 0) const;
+
+ /// \brief Returns a new state with all argument regions invalidated.
+ ///
+ /// This accepts an alternate state in case some processing has already
+ /// occurred.
+ 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;
+
+ /// Returns a copy of this CallEvent, but using the given state.
+ CallEventRef<> cloneWithState(ProgramStateRef NewState) const {
+ return cloneWithState<CallEvent>(NewState);
+ }
+
+ /// \brief Returns true if this is a statement that can be considered for
+ /// inlining.
+ ///
+ /// FIXME: This should go away once CallEvents are cheap and easy to
+ /// construct from ExplodedNodes.
+ static bool mayBeInlined(const Stmt *S);
+
+ // Iterator access to formal parameters and their types.
+private:
+ typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun;
+
+public:
+ typedef const ParmVarDecl * const *param_iterator;
+
+ /// Returns an iterator over the call's formal parameters.
+ ///
+ /// If UseDefinitionParams is set, this will return the parameter decls
+ /// used in the callee's definition (suitable for inlining). Most of the
+ /// time it is better to use the decl found by name lookup, which likely
+ /// carries more annotations.
+ ///
+ /// Remember that the number of formal parameters may not match the number
+ /// of arguments for all calls. However, the first parameter will always
+ /// correspond with the argument value returned by \c getArgSVal(0).
+ ///
+ /// 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() const =0;
+ /// \sa param_begin()
+ virtual param_iterator param_end() const = 0;
+
+ typedef llvm::mapped_iterator<param_iterator, get_type_fun>
+ param_type_iterator;
+
+ /// Returns an iterator over the types of the call's formal parameters.
+ ///
+ /// This uses the callee decl found by default name lookup rather than the
+ /// definition because it represents a public interface, and probably has
+ /// more annotations.
+ param_type_iterator param_type_begin() const {
+ return llvm::map_iterator(param_begin(),
+ get_type_fun(&ParmVarDecl::getType));
+ }
+ /// \sa param_type_begin()
+ param_type_iterator param_type_end() const {
+ return llvm::map_iterator(param_end(), get_type_fun(&ParmVarDecl::getType));
+ }
+
+ // For debugging purposes only
+ void dump(raw_ostream &Out) const;
+ LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); }
+
+ static bool classof(const CallEvent *) { return true; }
+};
+
+
+/// \brief Represents a call to any sort of function that might have a
+/// FunctionDecl.
+class AnyFunctionCall : public CallEvent {
+protected:
+ AnyFunctionCall(const Expr *E, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(E, St, LCtx) {}
+ AnyFunctionCall(const Decl *D, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(D, St, LCtx) {}
+ AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {}
+
+ virtual QualType getDeclaredResultType() const;
+
+public:
+ // This function is overridden by subclasses, but they must return
+ // a FunctionDecl.
+ virtual const FunctionDecl *getDecl() const {
+ return cast<FunctionDecl>(CallEvent::getDecl());
+ }
+
+ virtual RuntimeDefinition getRuntimeDefinition() const {
+ const FunctionDecl *FD = getDecl();
+ // Note that hasBody() will fill FD with the definition FunctionDecl.
+ if (FD && FD->hasBody(FD))
+ return RuntimeDefinition(FD);
+ return RuntimeDefinition();
+ }
+
+ virtual bool argumentsMayEscape() 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 &&
+ CA->getKind() <= CE_END_FUNCTION_CALLS;
+ }
+};
+
+/// \brief Represents a call to a non-C++ function, written as a CallExpr.
+class SimpleCall : public AnyFunctionCall {
+protected:
+ SimpleCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {}
+ SimpleCall(const SimpleCall &Other) : AnyFunctionCall(Other) {}
+
+public:
+ virtual const CallExpr *getOriginExpr() const {
+ return cast<CallExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ virtual const FunctionDecl *getDecl() const;
+
+ virtual unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
+
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() >= CE_BEG_SIMPLE_CALLS &&
+ CA->getKind() <= CE_END_SIMPLE_CALLS;
+ }
+};
+
+/// \brief Represents a C function or static C++ member function call.
+///
+/// Example: \c fun()
+class FunctionCall : public SimpleCall {
+ friend class CallEventManager;
+
+protected:
+ FunctionCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : SimpleCall(CE, St, LCtx) {}
+
+ FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+
+public:
+ virtual Kind getKind() const { return CE_Function; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_Function;
+ }
+};
+
+/// \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 AnyFunctionCall {
+protected:
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+ CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {}
+ CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(D, St, LCtx) {}
+
+
+ CXXInstanceCall(const CXXInstanceCall &Other) : AnyFunctionCall(Other) {}
+
+public:
+ /// \brief Returns the expression representing the implicit 'this' object.
+ virtual const Expr *getCXXThisExpr() const { return 0; }
+
+ /// \brief Returns the value of the implicit 'this' object.
+ virtual SVal getCXXThisVal() const {
+ const Expr *Base = getCXXThisExpr();
+ // FIXME: This doesn't handle an overloaded ->* operator.
+ if (!Base)
+ return UnknownVal();
+ return getSVal(Base);
+ }
+
+ virtual const FunctionDecl *getDecl() const;
+
+ virtual RuntimeDefinition 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;
+ }
+};
+
+/// \brief Represents a non-static C++ member function call.
+///
+/// Example: \c obj.fun()
+class CXXMemberCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
+protected:
+ CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(CE, St, LCtx) {}
+
+ CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+
+public:
+ virtual const CXXMemberCallExpr *getOriginExpr() const {
+ 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;
+
+ virtual Kind getKind() const { return CE_CXXMember; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMember;
+ }
+};
+
+/// \brief Represents a C++ overloaded operator call where the operator is
+/// implemented as a non-static member function.
+///
+/// Example: <tt>iter + 1</tt>
+class CXXMemberOperatorCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
+protected:
+ CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(CE, St, LCtx) {}
+
+ CXXMemberOperatorCall(const CXXMemberOperatorCall &Other)
+ : CXXInstanceCall(Other) {}
+ virtual void cloneTo(void *Dest) const {
+ new (Dest) CXXMemberOperatorCall(*this);
+ }
+
+public:
+ virtual const CXXOperatorCallExpr *getOriginExpr() const {
+ return cast<CXXOperatorCallExpr>(CXXInstanceCall::getOriginExpr());
+ }
+
+ virtual unsigned getNumArgs() const {
+ return getOriginExpr()->getNumArgs() - 1;
+ }
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index + 1);
+ }
+
+ virtual const Expr *getCXXThisExpr() const;
+
+ virtual Kind getKind() const { return CE_CXXMemberOperator; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMemberOperator;
+ }
+};
+
+/// \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 CXXInstanceCall {
+ 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)
+ : CXXInstanceCall(DD, St, LCtx) {
+ Data = Target;
+ Location = Trigger->getLocEnd();
+ }
+
+ CXXDestructorCall(const CXXDestructorCall &Other) : CXXInstanceCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
+
+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 Kind getKind() const { return CE_CXXDestructor; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXDestructor;
+ }
+};
+
+/// \brief Represents a call to a C++ constructor.
+///
+/// Example: \c T(1)
+class CXXConstructorCall : public AnyFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ /// Creates a constructor call.
+ ///
+ /// \param CE The constructor expression as written in the source.
+ /// \param Target The region where the object should be constructed. If NULL,
+ /// a new symbolic region will be used.
+ /// \param St The path-sensitive state at this point in the program.
+ /// \param LCtx The location context at this point in the program.
+ CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
+ ProgramStateRef St, const LocationContext *LCtx)
+ : AnyFunctionCall(CE, St, LCtx) {
+ Data = target;
+ }
+
+ CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
+
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+ virtual const CXXConstructExpr *getOriginExpr() const {
+ return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ virtual const CXXConstructorDecl *getDecl() const {
+ return getOriginExpr()->getConstructor();
+ }
+
+ virtual unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
+
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ /// \brief Returns the value of the implicit 'this' object.
+ 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) {
+ return CA->getKind() == CE_CXXConstructor;
+ }
+};
+
+/// \brief Represents the memory allocation call in a C++ new-expression.
+///
+/// This is a call to "operator new".
+class CXXAllocatorCall : public AnyFunctionCall {
+ friend class CallEventManager;
+
+protected:
+ CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : AnyFunctionCall(E, St, LCtx) {}
+
+ CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+
+public:
+ virtual const CXXNewExpr *getOriginExpr() const {
+ return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ virtual const FunctionDecl *getDecl() const {
+ return getOriginExpr()->getOperatorNew();
+ }
+
+ virtual unsigned getNumArgs() const {
+ return getOriginExpr()->getNumPlacementArgs() + 1;
+ }
+
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ // The first argument of an allocator call is the size of the allocation.
+ if (Index == 0)
+ return 0;
+ return getOriginExpr()->getPlacementArg(Index - 1);
+ }
+
+ virtual Kind getKind() const { return CE_CXXAllocator; }
+
+ static bool classof(const CallEvent *CE) {
+ return CE->getKind() == CE_CXXAllocator;
+ }
+};
+
+/// \brief Represents the ways an Objective-C message send can occur.
+//
+// Note to maintainers: OCM_Message should always be last, since it does not
+// need to fit in the Data field's low bits.
+enum ObjCMessageKind {
+ OCM_PropertyAccess,
+ OCM_Subscript,
+ OCM_Message
+};
+
+/// \brief Represents any expression that calls an Objective-C method.
+///
+/// This includes all of the kinds listed in ObjCMessageKind.
+class ObjCMethodCall : public CallEvent {
+ friend class CallEventManager;
+
+ const PseudoObjectExpr *getContainingPseudoObjectExpr() const;
+
+protected:
+ ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(Msg, St, LCtx) {
+ Data = 0;
+ }
+
+ ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); }
+
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+ virtual QualType getDeclaredResultType() const;
+
+ /// Check if the selector may have multiple definitions (may have overrides).
+ virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
+ Selector Sel) const;
+
+public:
+ virtual const ObjCMessageExpr *getOriginExpr() const {
+ return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
+ }
+ virtual const ObjCMethodDecl *getDecl() const {
+ return getOriginExpr()->getMethodDecl();
+ }
+ virtual unsigned getNumArgs() const {
+ return getOriginExpr()->getNumArgs();
+ }
+ virtual const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index);
+ }
+
+ bool isInstanceMessage() const {
+ return getOriginExpr()->isInstanceMessage();
+ }
+ ObjCMethodFamily getMethodFamily() const {
+ return getOriginExpr()->getMethodFamily();
+ }
+ Selector getSelector() const {
+ return getOriginExpr()->getSelector();
+ }
+
+ virtual SourceRange getSourceRange() const;
+
+ /// \brief Returns the value of the receiver at the time of this call.
+ SVal getReceiverSVal() const;
+
+ /// \brief Get the interface for the receiver.
+ ///
+ /// This works whether this is an instance message or a class message.
+ /// However, it currently just uses the static type of the receiver.
+ const ObjCInterfaceDecl *getReceiverInterface() const {
+ return getOriginExpr()->getReceiverInterface();
+ }
+
+ ObjCMessageKind getMessageKind() const;
+
+ bool isSetter() const {
+ switch (getMessageKind()) {
+ case OCM_Message:
+ llvm_unreachable("This is not a pseudo-object access!");
+ case OCM_PropertyAccess:
+ return getNumArgs() > 0;
+ case OCM_Subscript:
+ return getNumArgs() > 1;
+ }
+ llvm_unreachable("Unknown message kind");
+ }
+
+ virtual RuntimeDefinition getRuntimeDefinition() 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; }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_ObjCMessage;
+ }
+};
+
+
+/// \brief Manages the lifetime of CallEvent objects.
+///
+/// CallEventManager provides a way to create arbitrary CallEvents "on the
+/// stack" as if they were value objects by keeping a cache of CallEvent-sized
+/// memory blocks. The CallEvents created by CallEventManager are only valid
+/// for the lifetime of the OwnedCallEvent that holds them; right now these
+/// objects cannot be copied and ownership cannot be transferred.
+class CallEventManager {
+ friend class CallEvent;
+
+ llvm::BumpPtrAllocator &Alloc;
+ SmallVector<void *, 8> Cache;
+
+ void reclaim(const void *Memory) {
+ Cache.push_back(const_cast<void *>(Memory));
+ }
+
+ /// Returns memory that can be initialized as a CallEvent.
+ void *allocate() {
+ if (Cache.empty())
+ return Alloc.Allocate<FunctionCall>();
+ else
+ return Cache.pop_back_val();
+ }
+
+ template <typename T, typename Arg>
+ T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) {
+ return new (allocate()) T(A, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2>
+ T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
+ const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, A3, St, LCtx);
+ }
+
+public:
+ CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+
+
+ CallEventRef<>
+ getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
+
+
+ CallEventRef<>
+ getSimpleCall(const CallExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx);
+
+ CallEventRef<ObjCMethodCall>
+ getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<ObjCMethodCall>(E, State, LCtx);
+ }
+
+ CallEventRef<CXXConstructorCall>
+ getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXConstructorCall>(E, Target, State, LCtx);
+ }
+
+ CallEventRef<CXXDestructorCall>
+ getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+ const MemRegion *Target, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, State, LCtx);
+ }
+
+ CallEventRef<CXXAllocatorCall>
+ getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<CXXAllocatorCall>(E, State, LCtx);
+ }
+};
+
+
+template <typename T>
+CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const {
+ assert(isa<T>(*this) && "Cloning to unrelated type");
+ assert(sizeof(T) == sizeof(CallEvent) && "Subclasses may not add fields");
+
+ if (NewState == State)
+ return cast<T>(this);
+
+ CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+ T *Copy = static_cast<T *>(Mgr.allocate());
+ cloneTo(Copy);
+ assert(Copy->getKind() == this->getKind() && "Bad copy");
+
+ Copy->State = NewState;
+ return Copy;
+}
+
+inline void CallEvent::Release() const {
+ assert(RefCount > 0 && "Reference count is already zero.");
+ --RefCount;
+
+ if (RefCount > 0)
+ return;
+
+ CallEventManager &Mgr = State->getStateManager().getCallEventManager();
+ Mgr.reclaim(this);
+
+ this->~CallEvent();
+}
+
+} // end namespace ento
+} // end namespace clang
+
+namespace llvm {
+ // Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
+ template<class T> struct simplify_type< clang::ento::CallEventRef<T> > {
+ typedef const T *SimpleType;
+
+ static SimpleType
+ getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) {
+ return Val.getPtr();
+ }
+ };
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index b051d33cbd84..8c8e82ce20dd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -92,6 +92,10 @@ public:
return Pred->getLocationContext();
}
+ const StackFrameContext *getStackFrame() const {
+ return Pred->getStackFrame();
+ }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
@@ -132,6 +136,11 @@ public:
return 0;
}
+ /// \brief Get the value of arbitrary expressions at this point in the path.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
/// \brief Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 59136fc314ae..e75cdd87596b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -65,7 +65,7 @@ private:
/// WList - A set of queued nodes that need to be processed by the
/// worklist algorithm. It is up to the implementation of WList to decide
/// the order that nodes are processed.
- WorkList* WList;
+ OwningPtr<WorkList> WList;
/// BCounterFactory - A factory object for created BlockCounter objects.
/// These are used to record for key nodes in the ExplodedGraph the
@@ -104,23 +104,18 @@ private:
CoreEngine(const CoreEngine&); // Do not implement.
CoreEngine& operator=(const CoreEngine&);
- ExplodedNode *generateCallExitNode(ExplodedNode *N);
+ ExplodedNode *generateCallExitBeginNode(ExplodedNode *N);
public:
- /// Construct a CoreEngine object to analyze the provided CFG using
- /// a DFS exploration of the exploded graph.
+ /// Construct a CoreEngine object to analyze the provided CFG.
CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees,
FunctionSummariesTy *FS)
: SubEng(subengine), G(new ExplodedGraph()),
- WList(WorkList::makeBFS()),
+ WList(WorkList::makeDFS()),
BCounterFactory(G->getAllocator()),
AnalyzedCallees(VisitedCallees),
FunctionSummaries(FS){}
- ~CoreEngine() {
- delete WList;
- }
-
/// getGraph - Returns the exploded graph.
ExplodedGraph& getGraph() { return *G.get(); }
@@ -156,7 +151,7 @@ public:
blocksAborted.push_back(std::make_pair(block, node));
}
- WorkList *getWorkList() const { return WList; }
+ WorkList *getWorkList() const { return WList.get(); }
BlocksExhausted::const_iterator blocks_exhausted_begin() const {
return blocksExhausted.begin();
@@ -188,10 +183,10 @@ public:
// TODO: Turn into a calss.
struct NodeBuilderContext {
- CoreEngine &Eng;
+ const CoreEngine &Eng;
const CFGBlock *Block;
ExplodedNode *Pred;
- NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
+ NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
: Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); }
ExplodedNode *getPred() const { return Pred; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index 46fbb88212e3..1052d9491a96 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -133,6 +133,10 @@ public:
return getLocation().getLocationContext();
}
+ const StackFrameContext *getStackFrame() const {
+ return getLocationContext()->getCurrentStackFrame();
+ }
+
const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
CFG &getCFG() const { return *getLocationContext()->getCFG(); }
@@ -151,7 +155,7 @@ public:
static void Profile(llvm::FoldingSetNodeID &ID,
const ProgramPoint &Loc,
- ProgramStateRef state,
+ const ProgramStateRef &state,
bool IsSink) {
ID.Add(Loc);
ID.AddPointer(state.getPtr());
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 2a21a03e9a2d..4addb9d4ec49 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -41,8 +41,8 @@ class ObjCForCollectionStmt;
namespace ento {
class AnalysisManager;
-class CallOrObjCMessage;
-class ObjCMessage;
+class CallEvent;
+class SimpleCall;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -151,6 +151,25 @@ public:
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
+ /// \brief Run the analyzer's garbage collection - remove dead symbols and
+ /// bindings.
+ ///
+ /// \param Node - The predecessor node, from which the processing should
+ /// start.
+ /// \param Out - The returned set of output nodes.
+ /// \param ReferenceStmt - Run garbage collection using the symbols,
+ /// which are live before the given statement.
+ /// \param LC - The location context of the ReferenceStmt.
+ /// \param DiagnosticStmt - the statement used to associate the diagnostic
+ /// message, if any warnings should occur while removing the dead (leaks
+ /// are usually reported here).
+ /// \param K - In some cases it is possible to use PreStmt kind. (Do
+ /// not use it unless you know what you are doing.)
+ void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
+ const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *DiagnosticStmt,
+ ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
+
/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
void processCFGElement(const CFGElement E, ExplodedNode *Pred,
@@ -199,7 +218,8 @@ public:
/// Generate the entry node of the callee.
void processCallEnter(CallEnter CE, ExplodedNode *Pred);
- /// Generate the first post callsite node.
+ /// Generate the sequence of nodes that simulate the call exit and the post
+ /// visit for CallExpr.
void processCallExit(ExplodedNode *Pred);
/// Called by CoreEngine when the analysis worklist has terminated.
@@ -220,7 +240,7 @@ public:
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call);
+ const CallEvent *Call);
/// printState - Called by ProgramStateManager to print checker-specific data.
void printState(raw_ostream &Out, ProgramStateRef State,
@@ -265,6 +285,10 @@ public:
/// VisitAsmStmt - Transfer function logic for inline asm.
void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// VisitMSAsmStmt - Transfer function logic for MS inline asm.
+ void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
@@ -323,7 +347,7 @@ public:
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred,
+ void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
@@ -353,13 +377,10 @@ public:
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
- void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
- void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
- void VisitCXXDestructor(const CXXDestructorDecl *DD,
+ void VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest, const Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
@@ -373,13 +394,6 @@ public:
void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
-
- /// Synthesize CXXThisRegion.
- const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD,
- const StackFrameContext *SFC);
-
- const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl,
- const StackFrameContext *frameCtx);
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
@@ -416,19 +430,6 @@ public:
}
protected:
- void evalObjCMessage(StmtNodeBuilder &Bldr, const ObjCMessage &msg,
- ExplodedNode *Pred, ProgramStateRef state,
- bool GenSink);
-
- ProgramStateRef invalidateArguments(ProgramStateRef State,
- const CallOrObjCMessage &Call,
- const LocationContext *LC);
-
- ProgramStateRef MarkBranch(ProgramStateRef state,
- const Stmt *Terminator,
- const LocationContext *LCtx,
- bool branchTaken);
-
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
@@ -455,6 +456,21 @@ public:
void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
const ProgramPointTag *tag = 0);
+
+ /// \brief Create a new state in which the call return value is binded to the
+ /// call origin expression.
+ ProgramStateRef bindReturnValue(const CallEvent &Call,
+ 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 CallEvent &Call);
+
+ /// \brief Default implementation of call evaluation.
+ void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
+ const CallEvent &Call);
private:
void evalLoadCommon(ExplodedNodeSet &Dst,
const Expr *NodeEx, /* Eventually will be a CFGStmt */
@@ -474,8 +490,20 @@ private:
ProgramStateRef St, SVal location,
const ProgramPointTag *tag, bool isLoad);
- bool shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred);
- bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+ bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
+ bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
+ ExplodedNode *Pred, ProgramStateRef State);
+
+ /// \brief Conservatively evaluate call by invalidating regions and binding
+ /// a conjured return value.
+ void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
+ ExplodedNode *Pred, ProgramStateRef State);
+
+ /// \brief Either inline or process the call conservatively (or both), based
+ /// on DynamicDispatchBifurcation data.
+ void BifurcateCall(const MemRegion *BifurReg,
+ const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
+ ExplodedNode *Pred);
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index 42adff3e2b94..cf4a6929a3aa 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -14,15 +14,16 @@
#ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H
#define LLVM_CLANG_GR_FUNCTIONSUMMARY_H
+#include <deque>
#include "clang/AST/Decl.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/BitVector.h"
namespace clang {
namespace ento {
-typedef llvm::SmallPtrSet<Decl*, 24> SetOfDecls;
-typedef llvm::SmallPtrSet<const Decl*, 24> SetOfConstDecls;
+typedef std::deque<Decl*> SetOfDecls;
+typedef llvm::DenseSet<const Decl*> SetOfConstDecls;
class FunctionSummariesTy {
struct FunctionSummary {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 87bc0df0908f..01218effff90 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_MEMREGION_H
#define LLVM_CLANG_GR_MEMREGION_H
+#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ExprObjC.h"
@@ -51,11 +52,21 @@ class RegionOffset {
int64_t Offset;
public:
- RegionOffset(const MemRegion *r) : R(r), Offset(0) {}
+ enum { Symbolic = INT64_MAX };
+
+ RegionOffset() : R(0) {}
RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {}
const MemRegion *getRegion() const { return R; }
- int64_t getOffset() const { return Offset; }
+
+ bool hasSymbolicOffset() const { return Offset == Symbolic; }
+
+ int64_t getOffset() const {
+ assert(!hasSymbolicOffset());
+ return Offset;
+ }
+
+ bool isValid() const { return R; }
};
//===----------------------------------------------------------------------===//
@@ -127,7 +138,7 @@ public:
const MemRegion *getBaseRegion() const;
- const MemRegion *StripCasts() const;
+ const MemRegion *StripCasts(bool StripBaseCasts = true) const;
bool hasGlobalsOrParametersStorage() const;
@@ -147,8 +158,11 @@ public:
void dump() const;
+ /// \brief Returns true if this region can be printed in a user-friendly way.
+ virtual bool canPrintPretty() const;
+
/// \brief Print the region for use in diagnostics.
- virtual void dumpPretty(raw_ostream &os) const;
+ virtual void printPretty(raw_ostream &os) const;
Kind getKind() const { return kind; }
@@ -197,8 +211,9 @@ public:
}
};
-/// \class The region of the static variables within the current CodeTextRegion
+/// \brief The region of the static variables within the current CodeTextRegion
/// scope.
+///
/// Currently, only the static locals are placed there, so we know that these
/// variables do not get invalidated by calls to other functions.
class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
@@ -221,7 +236,7 @@ public:
}
};
-/// \class The region for all the non-static global variables.
+/// \brief The region for all the non-static global variables.
///
/// This class is further split into subclasses for efficient implementation of
/// invalidating a set of related global values as is done in
@@ -236,8 +251,6 @@ protected:
public:
- void dumpToStream(raw_ostream &os) const;
-
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES &&
@@ -245,7 +258,7 @@ public:
}
};
-/// \class The region containing globals which are defined in system/external
+/// \brief The region containing globals which are defined in system/external
/// headers and are considered modifiable by system calls (ex: errno).
class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion {
friend class MemRegionManager;
@@ -262,7 +275,7 @@ public:
}
};
-/// \class The region containing globals which are considered not to be modified
+/// \brief The region containing globals which are considered not to be modified
/// or point to data which could be modified as a result of a function call
/// (system or internal). Ex: Const global scalars would be modeled as part of
/// this region. This region also includes most system globals since they have
@@ -282,7 +295,7 @@ public:
}
};
-/// \class The region containing globals which can be modified by calls to
+/// \brief The region containing globals which can be modified by calls to
/// "internally" defined functions - (for now just) functions other then system
/// calls.
class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion {
@@ -307,6 +320,9 @@ class HeapSpaceRegion : public MemSpaceRegion {
HeapSpaceRegion(MemRegionManager *mgr)
: MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
public:
+
+ void dumpToStream(raw_ostream &os) const;
+
static bool classof(const MemRegion *R) {
return R->getKind() == HeapSpaceRegionKind;
}
@@ -318,6 +334,9 @@ class UnknownSpaceRegion : public MemSpaceRegion {
UnknownSpaceRegion(MemRegionManager *mgr)
: MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
public:
+
+ void dumpToStream(raw_ostream &os) const;
+
static bool classof(const MemRegion *R) {
return R->getKind() == UnknownSpaceRegionKind;
}
@@ -351,6 +370,9 @@ class StackLocalsSpaceRegion : public StackSpaceRegion {
StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
public:
+
+ void dumpToStream(raw_ostream &os) const;
+
static bool classof(const MemRegion *R) {
return R->getKind() == StackLocalsSpaceRegionKind;
}
@@ -363,6 +385,9 @@ private:
StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
public:
+
+ void dumpToStream(raw_ostream &os) const;
+
static bool classof(const MemRegion *R) {
return R->getKind() == StackArgumentsSpaceRegionKind;
}
@@ -478,6 +503,8 @@ public:
return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
}
+ DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
@@ -579,25 +606,37 @@ class BlockDataRegion : public SubRegion {
const BlockTextRegion *BC;
const LocationContext *LC; // Can be null */
void *ReferencedVars;
+ void *OriginalVars;
BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
const MemRegion *sreg)
- : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {}
+ : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ ReferencedVars(0), OriginalVars(0) {}
-public:
+public:
const BlockTextRegion *getCodeRegion() const { return BC; }
const BlockDecl *getDecl() const { return BC->getDecl(); }
class referenced_vars_iterator {
const MemRegion * const *R;
+ const MemRegion * const *OriginalR;
public:
- explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {}
+ explicit referenced_vars_iterator(const MemRegion * const *r,
+ const MemRegion * const *originalR)
+ : R(r), OriginalR(originalR) {}
operator const MemRegion * const *() const {
return R;
}
-
+
+ const MemRegion *getCapturedRegion() const {
+ return *R;
+ }
+ const MemRegion *getOriginalRegion() const {
+ return *OriginalR;
+ }
+
const VarRegion* operator*() const {
return cast<VarRegion>(*R);
}
@@ -610,6 +649,7 @@ public:
}
referenced_vars_iterator &operator++() {
++R;
+ ++OriginalR;
return *this;
}
};
@@ -781,8 +821,6 @@ public:
const Decl *getDecl() const { return D; }
void Profile(llvm::FoldingSetNodeID& ID) const;
- DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
-
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS;
@@ -819,7 +857,8 @@ public:
return R->getKind() == VarRegionKind;
}
- void dumpPretty(raw_ostream &os) const;
+ bool canPrintPretty() const;
+ void printPretty(raw_ostream &os) const;
};
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
@@ -878,7 +917,9 @@ public:
}
void dumpToStream(raw_ostream &os) const;
- void dumpPretty(raw_ostream &os) const;
+
+ bool canPrintPretty() const;
+ void printPretty(raw_ostream &os) const;
};
class ObjCIvarRegion : public DeclRegion {
@@ -1106,8 +1147,11 @@ public:
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
const LocationContext *LC);
- /// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
- const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
+ /// \brief Retrieve or create a "symbolic" memory region.
+ const SymbolicRegion* getSymbolicRegion(SymbolRef Sym);
+
+ /// \brief Return a unique symbolic region belonging to heap memory space.
+ const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym);
const StringRegion *getStringRegion(const StringLiteral* Str);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
deleted file mode 100644
index d8aec0991d9a..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ /dev/null
@@ -1,293 +0,0 @@
-//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ObjCMessage which serves as a common wrapper for ObjC
-// message expressions or implicit messages for loading/storing ObjC properties.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
-#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
-
-namespace clang {
-namespace ento {
-using llvm::StrInStrNoCase;
-
-/// \brief Represents both explicit ObjC message expressions and implicit
-/// messages that are sent for handling properties in dot syntax.
-class ObjCMessage {
- const ObjCMessageExpr *Msg;
- const ObjCPropertyRefExpr *PE;
- const bool IsPropSetter;
-public:
- ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
-
- ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
- bool isSetter = false)
- : Msg(E), PE(pe), IsPropSetter(isSetter) {
- assert(E && "should not be initialized with null expression");
- }
-
- bool isValid() const { return Msg; }
-
- bool isPureMessageExpr() const { return !PE; }
-
- bool isPropertyGetter() const { return PE && !IsPropSetter; }
-
- bool isPropertySetter() const {
- return IsPropSetter;
- }
-
- const Expr *getMessageExpr() const {
- return Msg;
- }
-
- QualType getType(ASTContext &ctx) const {
- return Msg->getType();
- }
-
- QualType getResultType(ASTContext &ctx) const {
- if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
- return MD->getResultType();
- return getType(ctx);
- }
-
- ObjCMethodFamily getMethodFamily() const {
- return Msg->getMethodFamily();
- }
-
- Selector getSelector() const {
- return Msg->getSelector();
- }
-
- const Expr *getInstanceReceiver() const {
- return Msg->getInstanceReceiver();
- }
-
- SVal getInstanceReceiverSVal(ProgramStateRef State,
- const LocationContext *LC) const {
- if (!isInstanceMessage())
- return UndefinedVal();
- if (const Expr *Ex = getInstanceReceiver())
- return State->getSValAsScalarOrLoc(Ex, LC);
-
- // An instance message with no expression means we are sending to super.
- // In this case the object reference is the same as 'self'.
- const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
- assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
- return State->getSVal(State->getRegion(SelfDecl, LC));
- }
-
- bool isInstanceMessage() const {
- return Msg->isInstanceMessage();
- }
-
- const ObjCMethodDecl *getMethodDecl() const {
- return Msg->getMethodDecl();
- }
-
- const ObjCInterfaceDecl *getReceiverInterface() const {
- return Msg->getReceiverInterface();
- }
-
- SourceLocation getSuperLoc() const {
- if (PE)
- return PE->getReceiverLocation();
- return Msg->getSuperLoc();
- }
-
- SourceRange getSourceRange() const LLVM_READONLY {
- if (PE)
- return PE->getSourceRange();
- return Msg->getSourceRange();
- }
-
- unsigned getNumArgs() const {
- return Msg->getNumArgs();
- }
-
- SVal getArgSVal(unsigned i,
- const LocationContext *LCtx,
- ProgramStateRef state) const {
- assert(i < getNumArgs() && "Invalid index for argument");
- return state->getSVal(Msg->getArg(i), LCtx);
- }
-
- QualType getArgType(unsigned i) const {
- assert(i < getNumArgs() && "Invalid index for argument");
- return Msg->getArg(i)->getType();
- }
-
- const Expr *getArgExpr(unsigned i) const {
- assert(i < getNumArgs() && "Invalid index for argument");
- return Msg->getArg(i);
- }
-
- SourceRange getArgSourceRange(unsigned i) const {
- const Expr *argE = getArgExpr(i);
- return argE->getSourceRange();
- }
-
- SourceRange getReceiverSourceRange() const {
- if (PE) {
- if (PE->isObjectReceiver())
- return PE->getBase()->getSourceRange();
- }
- else {
- return Msg->getReceiverRange();
- }
-
- // FIXME: This isn't a range.
- return PE->getReceiverLocation();
- }
-};
-
-/// \brief Common wrapper for a call expression, ObjC message, or C++
-/// constructor, mainly to provide a common interface for their arguments.
-class CallOrObjCMessage {
- llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
- ObjCMessage Msg;
- ProgramStateRef State;
- const LocationContext *LCtx;
-public:
- CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
- const LocationContext *lctx)
- : CallE(callE), State(state), LCtx(lctx) {}
- CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
- const LocationContext *lctx)
- : CallE(consE), State(state), LCtx(lctx) {}
- CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
- const LocationContext *lctx)
- : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
-
- QualType getResultType(ASTContext &ctx) const;
-
- bool isFunctionCall() const {
- return CallE && CallE.is<const CallExpr *>();
- }
-
- bool isCXXConstructExpr() const {
- return CallE && CallE.is<const CXXConstructExpr *>();
- }
-
- bool isObjCMessage() const {
- return !CallE;
- }
-
- bool isCXXCall() const {
- const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
- return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
- }
-
- /// Check if the callee is declared in the system header.
- bool isInSystemHeader() const {
- if (const Decl *FD = getDecl()) {
- const SourceManager &SM =
- State->getStateManager().getContext().getSourceManager();
- return SM.isInSystemHeader(FD->getLocation());
- }
- return false;
- }
-
- const Expr *getOriginExpr() const {
- if (!CallE)
- return Msg.getMessageExpr();
- if (const CXXConstructExpr *Ctor =
- CallE.dyn_cast<const CXXConstructExpr *>())
- return Ctor;
- return CallE.get<const CallExpr *>();
- }
-
- SVal getFunctionCallee() const;
- SVal getCXXCallee() const;
- SVal getInstanceMessageReceiver(const LocationContext *LC) const;
-
- /// Get the declaration of the function or method.
- const Decl *getDecl() const;
-
- unsigned getNumArgs() const {
- if (!CallE)
- return Msg.getNumArgs();
- if (const CXXConstructExpr *Ctor =
- CallE.dyn_cast<const CXXConstructExpr *>())
- return Ctor->getNumArgs();
- return CallE.get<const CallExpr *>()->getNumArgs();
- }
-
- SVal getArgSVal(unsigned i) const {
- assert(i < getNumArgs());
- if (!CallE)
- return Msg.getArgSVal(i, LCtx, State);
- return State->getSVal(getArg(i), LCtx);
- }
-
- const Expr *getArg(unsigned i) const {
- assert(i < getNumArgs());
- if (!CallE)
- return Msg.getArgExpr(i);
- if (const CXXConstructExpr *Ctor =
- CallE.dyn_cast<const CXXConstructExpr *>())
- return Ctor->getArg(i);
- return CallE.get<const CallExpr *>()->getArg(i);
- }
-
- SourceRange getArgSourceRange(unsigned i) const {
- assert(i < getNumArgs());
- if (CallE)
- return getArg(i)->getSourceRange();
- return Msg.getArgSourceRange(i);
- }
-
- SourceRange getReceiverSourceRange() const {
- assert(isObjCMessage());
- return Msg.getReceiverSourceRange();
- }
-
- /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics
- /// function that allows objects to escape.
- ///
- /// Many methods allow a tracked object to escape. For example:
- ///
- /// CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
- /// CFDictionaryAddValue(y, key, x);
- ///
- /// We handle this and similar cases with the following heuristic. If the
- /// function name contains "InsertValue", "SetValue", "AddValue",
- /// "AppendValue", or "SetAttribute", then we assume that arguments may
- /// escape.
- //
- // TODO: To reduce false negatives here, we should track the container
- // allocation site and check if a proper deallocator was set there.
- static bool isCFCGAllowingEscape(StringRef FName) {
- if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
- if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
- StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
- StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
- StrInStrNoCase(FName, "WithData") != StringRef::npos ||
- StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
- StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {
- return true;
- }
- return false;
- }
-};
-
-}
-}
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 360d6486f966..d36aa1bd1bcb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -35,7 +35,8 @@ class ASTContext;
namespace ento {
-class CallOrObjCMessage;
+class CallEvent;
+class CallEventManager;
typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
SubEngine&);
@@ -49,13 +50,34 @@ template <typename T> struct ProgramStatePartialTrait;
template <typename T> struct ProgramStateTrait {
typedef typename T::data_type data_type;
- static inline void *GDMIndex() { return &T::TagInt; }
static inline void *MakeVoidPtr(data_type D) { return (void*) D; }
static inline data_type MakeData(void *const* P) {
return P ? (data_type) *P : (data_type) 0;
}
};
+/// \class Stores the dynamic type information.
+/// Information about type of an object at runtime. This is used by dynamic
+/// dispatch implementation.
+class DynamicTypeInfo {
+ QualType T;
+ bool CanBeASubClass;
+
+public:
+ DynamicTypeInfo() : T(QualType()) {}
+ DynamicTypeInfo(QualType WithType, bool CanBeSub = true):
+ T(WithType), CanBeASubClass(CanBeSub) {}
+ QualType getType() { return T; }
+ bool canBeASubClass() { return CanBeASubClass; }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ T.Profile(ID);
+ ID.AddInteger((unsigned)CanBeASubClass);
+ }
+ bool operator==(const DynamicTypeInfo &X) const {
+ return T == X.T && CanBeASubClass == X.CanBeASubClass;
+ }
+};
+
/// \class ProgramState
/// ProgramState - This class encapsulates:
///
@@ -220,12 +242,12 @@ public:
const Expr *E, unsigned BlockCount,
const LocationContext *LCtx,
StoreManager::InvalidatedSymbols *IS = 0,
- const CallOrObjCMessage *Call = 0) const;
+ const CallEvent *Call = 0) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
- ProgramStateRef enterStackFrame(const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx) const;
+ ProgramStateRef enterStackFrame(const CallEvent &Call,
+ const StackFrameContext *CalleeCtx) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
@@ -239,6 +261,9 @@ public:
/// Get the lvalue for a field reference.
SVal getLValue(const FieldDecl *decl, SVal Base) const;
+ /// Get the lvalue for an indirect field reference.
+ SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const;
+
/// Get the lvalue for an array index.
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
@@ -310,6 +335,20 @@ public:
bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
+ /// \brief Get dynamic type information for a region.
+ DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const;
+
+ /// \brief Set dynamic type information of the region; return the new state.
+ ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg,
+ DynamicTypeInfo NewTy) const;
+
+ /// \brief Set dynamic type information of the region; return the new state.
+ ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg,
+ QualType NewTy,
+ bool CanBeSubClassed = true) const {
+ return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy, CanBeSubClassed));
+ }
+
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
@@ -382,7 +421,7 @@ private:
const Expr *E, unsigned BlockCount,
const LocationContext *LCtx,
StoreManager::InvalidatedSymbols &IS,
- const CallOrObjCMessage *Call) const;
+ const CallEvent *Call) const;
};
//===----------------------------------------------------------------------===//
@@ -412,6 +451,9 @@ private:
/// Object that manages the data for all created SVals.
OwningPtr<SValBuilder> svalBuilder;
+ /// Manages memory for created CallEvents.
+ OwningPtr<CallEventManager> CallEventMgr;
+
/// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
@@ -423,28 +465,7 @@ public:
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
- SubEngine &subeng)
- : Eng(&subeng),
- EnvMgr(alloc),
- GDMFactory(alloc),
- svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
- Alloc(alloc) {
- StoreMgr.reset((*CreateStoreManager)(*this));
- ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
- }
-
- ProgramStateManager(ASTContext &Ctx,
- StoreManagerCreator CreateStoreManager,
- ConstraintManager* ConstraintManagerPtr,
- llvm::BumpPtrAllocator& alloc)
- : Eng(0),
- EnvMgr(alloc),
- GDMFactory(alloc),
- svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
- Alloc(alloc) {
- StoreMgr.reset((*CreateStoreManager)(*this));
- ConstraintMgr.reset(ConstraintManagerPtr);
- }
+ SubEngine &subeng);
~ProgramStateManager();
@@ -480,6 +501,8 @@ public:
return svalBuilder->getRegionManager();
}
+ CallEventManager &getCallEventManager() { return *CallEventMgr; }
+
StoreManager& getStoreManager() { return *StoreMgr; }
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
SubEngine* getOwningEngine() { return Eng; }
@@ -650,6 +673,18 @@ inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueField(D, Base);
}
+inline SVal ProgramState::getLValue(const IndirectFieldDecl *D,
+ SVal Base) const {
+ StoreManager &SM = *getStateManager().StoreMgr;
+ for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
+ E = D->chain_end();
+ I != E; ++I) {
+ Base = SM.getLValueField(cast<FieldDecl>(*I), Base);
+ }
+
+ return Base;
+}
+
inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
@@ -672,7 +707,7 @@ ProgramState::getSValAsScalarOrLoc(const Stmt *S,
const LocationContext *LCtx) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
- if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType())
+ if (Ex->isGLValue() || Loc::isLocType(T) || T->isIntegerType())
return getSVal(S, LCtx);
}
@@ -765,14 +800,12 @@ CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
/// \class ScanReachableSymbols
/// A Utility class that allows to visit the reachable symbols using a custom
/// SymbolVisitor.
-class ScanReachableSymbols : public SubRegionMap::Visitor {
- virtual void anchor();
+class ScanReachableSymbols {
typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
VisitedItems visited;
ProgramStateRef state;
SymbolVisitor &visitor;
- OwningPtr<SubRegionMap> SRM;
public:
ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v)
@@ -782,11 +815,6 @@ public:
bool scan(SVal val);
bool scan(const MemRegion *R);
bool scan(const SymExpr *sym);
-
- // From SubRegionMap::Visitor.
- bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) {
- return scan(SubRegion);
- }
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 4ad36f9dbb1d..83c3a5634586 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_GR_SVALBUILDER
#define LLVM_CLANG_GR_SVALBUILDER
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -78,7 +79,7 @@ public:
// FIXME: Remove the second disjunct when we support symbolic
// truncation/extension.
return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) ||
- (Ty2->isIntegerType() && Ty2->isIntegerType()));
+ (Ty1->isIntegerType() && Ty2->isIntegerType()));
}
SVal evalCast(SVal val, QualType castTy, QualType originalType);
@@ -107,12 +108,9 @@ public:
/// that value is returned. Otherwise, returns NULL.
virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
- /// Handles generation of the value in case the builder is not smart enough to
- /// handle the given binary expression. Depending on the state, decides to
- /// either keep the expression or forget the history and generate an
- /// UnknownVal.
- SVal makeGenericVal(ProgramStateRef state, BinaryOperator::Opcode op,
- NonLoc lhs, NonLoc rhs, QualType resultTy);
+ /// Constructs a symbolic expression for two non-location values.
+ SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy);
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type);
@@ -185,6 +183,12 @@ public:
const LocationContext *LCtx,
QualType type,
unsigned visitCount);
+ /// \brief Conjure a symbol representing heap allocated memory region.
+ ///
+ /// Note, the expression should represent a location.
+ DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned Count);
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
SymbolRef parentSymbol, const TypedValueRegion *region);
@@ -307,6 +311,13 @@ public:
return loc::ConcreteInt(BasicVals.getValue(integer));
}
+ /// Return a memory region for the 'this' object reference.
+ loc::MemRegionVal getCXXThis(const CXXMethodDecl *D,
+ const StackFrameContext *SFC);
+
+ /// Return a memory region for the 'this' object reference.
+ loc::MemRegionVal getCXXThis(const CXXRecordDecl *D,
+ const StackFrameContext *SFC);
};
SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index ce3eb1db8365..e0b5f64b900b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -68,7 +68,6 @@ protected:
public:
explicit SVal() : Data(0), Kind(0) {}
- ~SVal() {}
/// BufferTy - A temporary buffer to hold a set of SVals.
typedef SmallVector<SVal,5> BufferTy;
@@ -164,13 +163,10 @@ public:
class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
- UndefinedVal(const void *D) : SVal(UndefinedKind, D) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UndefinedKind;
}
-
- const void *getData() const { return Data; }
};
class DefinedOrUnknownSVal : public SVal {
@@ -326,16 +322,22 @@ class LocAsInteger : public NonLoc {
public:
Loc getLoc() const {
- return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ return cast<Loc>(D->first);
}
const Loc& getPersistentLoc() const {
- const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ const SVal& V = D->first;
return cast<Loc>(V);
}
unsigned getNumBits() const {
- return ((std::pair<SVal, unsigned>*) Data)->second;
+ const std::pair<SVal, uintptr_t> *D =
+ static_cast<const std::pair<SVal, uintptr_t> *>(Data);
+ return D->second;
}
// Implement isa<T> support.
@@ -401,7 +403,7 @@ public:
namespace loc {
-enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind, ObjCPropRefKind };
+enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
class GotoLabel : public Loc {
public:
@@ -431,7 +433,7 @@ public:
}
/// \brief Get the underlining region and strip casts.
- const MemRegion* stripCasts() const;
+ const MemRegion* stripCasts(bool StripBaseCasts = true) const;
template <typename REGION>
const REGION* getRegionAs() const {
@@ -480,28 +482,6 @@ public:
}
};
-/// \brief Pseudo-location SVal used by the ExprEngine to simulate a "load" or
-/// "store" of an ObjC property for the dot syntax.
-class ObjCPropRef : public Loc {
-public:
- explicit ObjCPropRef(const ObjCPropertyRefExpr *E)
- : Loc(ObjCPropRefKind, E) {}
-
- const ObjCPropertyRefExpr *getPropRefExpr() const {
- return static_cast<const ObjCPropertyRefExpr *>(Data);
- }
-
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == ObjCPropRefKind;
- }
-
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == ObjCPropRefKind;
- }
-};
-
} // end ento::loc namespace
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 5315f4b7420a..138a590b1b24 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -29,10 +29,10 @@ class StackFrameContext;
namespace ento {
-class CallOrObjCMessage;
+class CallEvent;
class ProgramState;
class ProgramStateManager;
-class SubRegionMap;
+class ScanReachableSymbols;
class StoreManager {
protected:
@@ -49,7 +49,7 @@ public:
virtual ~StoreManager() {}
/// Return the value bound to specified location in a given state.
- /// \param[in] state The analysis state.
+ /// \param[in] store The analysis state.
/// \param[in] loc The symbolic memory location.
/// \param[in] T An optional type that provides a hint indicating the
/// expected type of the returned value. This is used if the value is
@@ -58,12 +58,12 @@ public:
virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0;
/// Return a state with the specified value bound to the given location.
- /// \param[in] state The analysis state.
+ /// \param[in] store The analysis state.
/// \param[in] loc The symbolic memory location.
/// \param[in] val The value to bind to location \c loc.
- /// \return A pointer to a ProgramState object that contains the same bindings as
- /// \c state with the addition of having the value specified by \c val bound
- /// to the location given for \c loc.
+ /// \return A pointer to a ProgramState object that contains the same
+ /// bindings as \c state with the addition of having the value specified
+ /// by \c val bound to the location given for \c loc.
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V);
@@ -85,11 +85,6 @@ public:
/// used to query and manipulate MemRegion objects.
MemRegionManager& getRegionManager() { return MRMgr; }
- /// getSubRegionMap - Returns an opaque map object that clients can query
- /// to get the subregions of a given MemRegion object. It is the
- // caller's responsibility to 'delete' the returned map.
- virtual SubRegionMap *getSubRegionMap(Store store) = 0;
-
virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) {
return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
}
@@ -120,7 +115,10 @@ public:
virtual SVal ArrayToPointer(Loc Array) = 0;
/// Evaluates DerivedToBase casts.
- virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) = 0;
+ SVal evalDerivedToBase(SVal derived, const CastExpr *Cast);
+
+ /// Evaluates a derived-to-base cast through a single level of derivation.
+ virtual SVal evalDerivedToBase(SVal derived, QualType derivedPtrType) = 0;
/// \brief Evaluates C++ dynamic_cast cast.
/// The callback may result in the following 3 scenarios:
@@ -133,15 +131,6 @@ public:
virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,
bool &Failed) = 0;
- class CastResult {
- ProgramStateRef state;
- const MemRegion *region;
- public:
- ProgramStateRef getState() const { return state; }
- const MemRegion* getRegion() const { return region; }
- CastResult(ProgramStateRef s, const MemRegion* r = 0) : state(s), region(r){}
- };
-
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
/// castRegion - Used by ExprEngine::VisitCast to handle casts from
@@ -176,8 +165,7 @@ public:
/// invalidate additional regions that may have changed based on accessing
/// the given regions. Optionally, invalidates non-static globals as well.
/// \param[in] store The initial store
- /// \param[in] Begin A pointer to the first region to invalidate.
- /// \param[in] End A pointer just past the last region to invalidate.
+ /// \param[in] Regions The regions to invalidate.
/// \param[in] E The current statement being evaluated. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Count The current block count. Used to conjure
@@ -186,7 +174,7 @@ public:
/// accessible. Pass \c NULL if this information will not be used.
/// \param[in] Call The call expression which will be used to determine which
/// globals should get invalidated.
- /// \param[in,out] Regions A vector to fill with any regions being
+ /// \param[in,out] Invalidated A vector to fill with any regions being
/// invalidated. This should include any regions explicitly invalidated
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
@@ -195,14 +183,20 @@ public:
const Expr *E, unsigned Count,
const LocationContext *LCtx,
InvalidatedSymbols &IS,
- const CallOrObjCMessage *Call,
+ const CallEvent *Call,
InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
- virtual StoreRef enterStackFrame(ProgramStateRef state,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx);
+ StoreRef enterStackFrame(Store store,
+ const CallEvent &Call,
+ const StackFrameContext *CalleeCtx);
+
+ /// Finds the transitive closure of symbols within the given region.
+ ///
+ /// Returns false if the visitor aborted the scan.
+ virtual bool scanReachableSymbols(Store S, const MemRegion *R,
+ ScanReachableSymbols &Visitor) = 0;
virtual void print(Store store, raw_ostream &Out,
const char* nl, const char *sep) = 0;
@@ -275,24 +269,6 @@ inline StoreRef &StoreRef::operator=(StoreRef const &newStore) {
return *this;
}
-// FIXME: Do we still need this?
-/// SubRegionMap - An abstract interface that represents a queryable map
-/// between MemRegion objects and their subregions.
-class SubRegionMap {
- virtual void anchor();
-public:
- virtual ~SubRegionMap() {}
-
- class Visitor {
- virtual void anchor();
- public:
- virtual ~Visitor() {}
- virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
- };
-
- virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
-};
-
// FIXME: Do we need to pass ProgramStateManager anymore?
StoreManager *CreateRegionStoreManager(ProgramStateManager& StMgr);
StoreManager *CreateFieldsOnlyRegionStoreManager(ProgramStateManager& StMgr);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index baf57d49060c..68b81f19a4fd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -105,7 +105,7 @@ public:
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
- const CallOrObjCMessage *Call) = 0;
+ const CallEvent *Call) = 0;
inline ProgramStateRef
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index c7de7eff8df2..5d27f8654eb0 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -94,6 +94,8 @@ public:
return symbol_iterator(this);
}
static symbol_iterator symbol_end() { return symbol_iterator(); }
+
+ unsigned computeComplexity() const;
};
typedef const SymExpr* SymbolRef;
@@ -553,6 +555,7 @@ public:
BasicValueFactory &getBasicVals() { return BV; }
};
+/// \brief A class responsible for cleaning up unused symbols.
class SymbolReaper {
enum SymbolStatus {
NotProcessed,
@@ -569,21 +572,26 @@ class SymbolReaper {
RegionSetTy RegionRoots;
- const LocationContext *LCtx;
+ const StackFrameContext *LCtx;
const Stmt *Loc;
SymbolManager& SymMgr;
StoreRef reapedStore;
llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache;
public:
+ /// \brief Construct a reaper object, which removes everything which is not
+ /// live before we execute statement s in the given location context.
+ ///
+ /// If the statement is NULL, everything is this and parent contexts is
+ /// considered live.
SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
StoreManager &storeMgr)
- : LCtx(ctx), Loc(s), SymMgr(symmgr), reapedStore(0, storeMgr) {}
+ : LCtx(ctx->getCurrentStackFrame()), Loc(s), SymMgr(symmgr),
+ reapedStore(0, storeMgr) {}
~SymbolReaper() {}
const LocationContext *getLocationContext() const { return LCtx; }
- const Stmt *getCurrentStatement() const { return Loc; }
bool isLive(SymbolRef sym);
bool isLiveRegion(const MemRegion *region);