aboutsummaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h360
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h183
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h231
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h81
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h117
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerProvider.h58
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h132
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h (renamed from include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h)18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h118
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h246
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h49
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h215
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h164
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h184
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (renamed from include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h)433
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h (renamed from include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h)57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h37
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h50
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h36
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h238
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h93
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h10
32 files changed, 1915 insertions, 1448 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 3acbcd685bc0..bfb7ef8964ea 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
-// PathDiagnostics for analyses based on GRState.
+// PathDiagnostics for analyses based on ProgramState.
//
//===----------------------------------------------------------------------===//
@@ -16,7 +16,9 @@
#define LLVM_CLANG_GR_BUGREPORTER
#include "clang/Basic/SourceLocation.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -26,121 +28,138 @@
namespace clang {
class ASTContext;
-class Diagnostic;
+class DiagnosticsEngine;
class Stmt;
class ParentMap;
namespace ento {
class PathDiagnostic;
-class PathDiagnosticPiece;
-class PathDiagnosticClient;
class ExplodedNode;
class ExplodedGraph;
+class BugReport;
class BugReporter;
class BugReporterContext;
class ExprEngine;
-class GRState;
class BugType;
//===----------------------------------------------------------------------===//
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
-class BugReporterVisitor : public llvm::FoldingSetNode {
+/// This class provides an interface through which checkers can create
+/// individual bug reports.
+class BugReport {
public:
- virtual ~BugReporterVisitor();
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BRC) = 0;
+ class NodeResolver {
+ public:
+ virtual ~NodeResolver() {}
+ virtual const ExplodedNode*
+ getOriginalNode(const ExplodedNode *N) = 0;
+ };
- virtual bool isOwnedByReporterContext() { return true; }
- virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
-};
+ typedef const SourceRange *ranges_iterator;
+ typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
+ typedef SmallVector<StringRef, 2> ExtraTextList;
-// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
-class BugReport : public BugReporterVisitor {
protected:
+ friend class BugReporter;
+ friend class BugReportEquivClass;
+
BugType& BT;
std::string ShortDescription;
std::string Description;
+ PathDiagnosticLocation Location;
const ExplodedNode *ErrorNode;
- mutable SourceRange R;
-
-protected:
- friend class BugReporter;
- friend class BugReportEquivClass;
+ SmallVector<SourceRange, 4> Ranges;
+ ExtraTextList ExtraText;
- virtual void Profile(llvm::FoldingSetNodeID& hash) const {
- hash.AddPointer(&BT);
- hash.AddInteger(getLocation().getRawEncoding());
- hash.AddString(Description);
- }
+ // Not the most efficient data structure, but we use an ImmutableList for the
+ // Callbacks because it is safe to make additions to list during iteration.
+ llvm::ImmutableList<BugReporterVisitor*>::Factory F;
+ llvm::ImmutableList<BugReporterVisitor*> Callbacks;
+ llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
- class NodeResolver {
- public:
- virtual ~NodeResolver() {}
- virtual const ExplodedNode*
- getOriginalNode(const ExplodedNode* N) = 0;
- };
-
- BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
- : BT(bt), Description(desc), ErrorNode(errornode) {}
+ BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
+ : BT(bt), Description(desc), ErrorNode(errornode),
+ Callbacks(F.getEmptyList()) {}
- BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
+ BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
const ExplodedNode *errornode)
- : BT(bt), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode) {}
+ : BT(bt), ShortDescription(shortDesc), Description(desc),
+ ErrorNode(errornode), Callbacks(F.getEmptyList()) {}
- virtual ~BugReport();
+ BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
+ : BT(bt), Description(desc), Location(l), ErrorNode(0),
+ Callbacks(F.getEmptyList()) {}
- virtual bool isOwnedByReporterContext() { return false; }
+ virtual ~BugReport();
const BugType& getBugType() const { return BT; }
BugType& getBugType() { return BT; }
- // FIXME: Perhaps this should be moved into a subclass?
- const ExplodedNode* getErrorNode() const { return ErrorNode; }
-
- // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
- // object.
- // FIXME: If we do need it, we can probably just make it private to
- // BugReporter.
- const Stmt* getStmt() const;
+ const ExplodedNode *getErrorNode() const { return ErrorNode; }
- const llvm::StringRef getDescription() const { return Description; }
+ const StringRef getDescription() const { return Description; }
- const llvm::StringRef getShortDescription() const {
+ const StringRef getShortDescription() const {
return ShortDescription.empty() ? Description : ShortDescription;
}
- // FIXME: Is this needed?
- virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
- return std::make_pair((const char**)0,(const char**)0);
+ /// \brief This allows for addition of meta data to the diagnostic.
+ ///
+ /// Currently, only the HTMLDiagnosticClient knows how to display it.
+ void addExtraText(StringRef S) {
+ ExtraText.push_back(S);
}
- // FIXME: Perhaps move this into a subclass.
- virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
- const ExplodedNode* N);
+ virtual const ExtraTextList &getExtraText() {
+ return ExtraText;
+ }
- /// getLocation - Return the "definitive" location of the reported bug.
+ /// \brief Return the "definitive" location of the reported bug.
+ ///
/// While a bug can span an entire path, usually there is a specific
/// location that can be used to identify where the key issue occurred.
/// This location is used by clients rendering diagnostics.
- virtual SourceLocation getLocation() const;
+ virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
- typedef const SourceRange *ranges_iterator;
+ const Stmt *getStmt() const;
+
+ /// \brief Add a range to a bug report.
+ ///
+ /// Ranges are used to highlight regions of interest in the source code.
+ /// They should be at the same source code line as the BugReport location.
+ /// By default, the source range of the statement corresponding to the error
+ /// node will be used; add a single invalid range to specify absence of
+ /// ranges.
+ void addRange(SourceRange R) {
+ assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
+ "to specify that the report does not have a range.");
+ Ranges.push_back(R);
+ }
- /// getRanges - Returns the source ranges associated with this bug.
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
+ /// \brief Get the SourceRanges associated with the report.
+ virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
- virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
- const ExplodedNode* PrevN,
- BugReporterContext& BR);
+ /// \brief Add custom or predefined bug report visitors to this report.
+ ///
+ /// The visitors should be used when the default trace is not sufficient.
+ /// For example, they allow constructing a more elaborate trace.
+ /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
+ /// registerFindLastStore(), registerNilReceiverVisitor(), and
+ /// registerVarDeclsLastStore().
+ void addVisitor(BugReporterVisitor *visitor);
- virtual void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N) {}
+ /// Iterators through the custom diagnostic visitors.
+ visitor_iterator visitor_begin() { return Callbacks.begin(); }
+ visitor_iterator visitor_end() { return Callbacks.end(); }
+
+ /// Profile to identify equivalent bug reports for error report coalescing.
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const;
};
//===----------------------------------------------------------------------===//
@@ -148,7 +167,7 @@ public:
//===----------------------------------------------------------------------===//
class BugReportEquivClass : public llvm::FoldingSetNode {
- // List of *owned* BugReport objects.
+ /// List of *owned* BugReport objects.
std::list<BugReport*> Reports;
friend class BugReporter;
@@ -166,9 +185,9 @@ public:
std::list<BugReport*>::iterator impl;
public:
iterator(std::list<BugReport*>::iterator i) : impl(i) {}
- iterator& operator++() { ++impl; return *this; }
- bool operator==(const iterator& I) const { return I.impl == impl; }
- bool operator!=(const iterator& I) const { return I.impl != impl; }
+ iterator &operator++() { ++impl; return *this; }
+ bool operator==(const iterator &I) const { return I.impl == impl; }
+ bool operator!=(const iterator &I) const { return I.impl != impl; }
BugReport* operator*() const { return *impl; }
BugReport* operator->() const { return *impl; }
};
@@ -177,9 +196,9 @@ public:
std::list<BugReport*>::const_iterator impl;
public:
const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
- const_iterator& operator++() { ++impl; return *this; }
- bool operator==(const const_iterator& I) const { return I.impl == impl; }
- bool operator!=(const const_iterator& I) const { return I.impl != impl; }
+ const_iterator &operator++() { ++impl; return *this; }
+ bool operator==(const const_iterator &I) const { return I.impl == impl; }
+ bool operator!=(const const_iterator &I) const { return I.impl != impl; }
const BugReport* operator*() const { return *impl; }
const BugReport* operator->() const { return *impl; }
};
@@ -191,78 +210,6 @@ public:
const_iterator end() const { return const_iterator(Reports.end()); }
};
-
-//===----------------------------------------------------------------------===//
-// Specialized subclasses of BugReport.
-//===----------------------------------------------------------------------===//
-
-// FIXME: Collapse this with the default BugReport class.
-class RangedBugReport : public BugReport {
- llvm::SmallVector<SourceRange, 4> Ranges;
-public:
- RangedBugReport(BugType& D, llvm::StringRef description,
- ExplodedNode *errornode)
- : BugReport(D, description, errornode) {}
-
- RangedBugReport(BugType& D, llvm::StringRef shortDescription,
- llvm::StringRef description, ExplodedNode *errornode)
- : BugReport(D, shortDescription, description, errornode) {}
-
- ~RangedBugReport();
-
- // FIXME: Move this out of line.
- void addRange(SourceRange R) {
- assert(R.isValid());
- Ranges.push_back(R);
- }
-
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
- return std::make_pair(Ranges.begin(), Ranges.end());
- }
-
- virtual void Profile(llvm::FoldingSetNodeID& hash) const {
- BugReport::Profile(hash);
- for (llvm::SmallVectorImpl<SourceRange>::const_iterator I =
- Ranges.begin(), E = Ranges.end(); I != E; ++I) {
- const SourceRange range = *I;
- if (!range.isValid())
- continue;
- hash.AddInteger(range.getBegin().getRawEncoding());
- hash.AddInteger(range.getEnd().getRawEncoding());
- }
- }
-};
-
-class EnhancedBugReport : public RangedBugReport {
-public:
- typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
- const ExplodedNode *N);
-
-private:
- typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
- Creators creators;
-
-public:
- EnhancedBugReport(BugType& D, llvm::StringRef description,
- ExplodedNode *errornode)
- : RangedBugReport(D, description, errornode) {}
-
- EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
- llvm::StringRef description, ExplodedNode *errornode)
- : RangedBugReport(D, shortDescription, description, errornode) {}
-
- ~EnhancedBugReport() {}
-
- void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
- for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
- I->first(BRC, I->second, N);
- }
-
- void addVisitorCreator(VisitorCreator creator, const void *data) {
- creators.push_back(std::make_pair(creator, data));
- }
-};
-
//===----------------------------------------------------------------------===//
// BugReporter and friends.
//===----------------------------------------------------------------------===//
@@ -270,12 +217,15 @@ public:
class BugReporterData {
public:
virtual ~BugReporterData();
- virtual Diagnostic& getDiagnostic() = 0;
- virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
- virtual ASTContext& getASTContext() = 0;
+ virtual DiagnosticsEngine& getDiagnostic() = 0;
+ virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
+ virtual ASTContext &getASTContext() = 0;
virtual SourceManager& getSourceManager() = 0;
};
+/// BugReporter is a utility class for generating PathDiagnostics for analysis.
+/// It collects the BugReports and BugTypes and knows how to generate
+/// and flush the corresponding diagnostics.
class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
@@ -288,9 +238,13 @@ private:
const Kind kind;
BugReporterData& D;
+ /// Generate and flush the diagnostics for the given bug report.
void FlushReport(BugReportEquivClass& EQ);
+ /// The set of bug reports tracked by the BugReporter.
llvm::FoldingSet<BugReportEquivClass> EQClasses;
+ /// A vector of BugReports for tracking the allocated pointers and cleanup.
+ std::vector<BugReportEquivClass *> EQClassesVector;
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
@@ -301,63 +255,71 @@ public:
D(d) {}
virtual ~BugReporter();
+ /// \brief Generate and flush diagnostics for all bug reports.
void FlushReports();
Kind getKind() const { return kind; }
- Diagnostic& getDiagnostic() {
+ DiagnosticsEngine& getDiagnostic() {
return D.getDiagnostic();
}
- PathDiagnosticClient* getPathDiagnosticClient() {
- return D.getPathDiagnosticClient();
+ PathDiagnosticConsumer* getPathDiagnosticConsumer() {
+ return D.getPathDiagnosticConsumer();
}
+ /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
typedef BugTypesTy::iterator iterator;
iterator begin() { return BugTypes.begin(); }
iterator end() { return BugTypes.end(); }
+ /// \brief Iterator over the set of BugReports tracked by the BugReporter.
typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
- ASTContext& getContext() { return D.getASTContext(); }
+ ASTContext &getContext() { return D.getASTContext(); }
SourceManager& getSourceManager() { return D.getSourceManager(); }
virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
- llvm::SmallVectorImpl<BugReport *> &bugReports) {}
+ SmallVectorImpl<BugReport *> &bugReports) {}
void Register(BugType *BT);
+ /// \brief Add the given report to the set of reports tracked by BugReporter.
+ ///
+ /// The reports are usually generated by the checkers. Further, they are
+ /// folded based on the profile value, which is done to coalesce similar
+ /// reports.
void EmitReport(BugReport *R);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
- llvm::StringRef BugStr, SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc) {
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc) {
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
- llvm::StringRef BugStr, SourceLocation Loc) {
+ void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ StringRef BugStr, PathDiagnosticLocation Loc) {
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
- SourceLocation Loc, SourceRange R) {
+ void EmitBasicReport(StringRef BugName, StringRef BugStr,
+ PathDiagnosticLocation Loc, SourceRange R) {
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
}
- void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
- llvm::StringRef BugStr, SourceLocation Loc,
+ void EmitBasicReport(StringRef BugName, StringRef Category,
+ StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange R) {
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
}
@@ -369,7 +331,7 @@ private:
/// \brief Returns a BugType that is associated with the given name and
/// category.
- BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
+ BugType *getBugTypeForName(StringRef name, StringRef category);
};
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
@@ -392,10 +354,10 @@ public:
/// getStateManager - Return the state manager used by the analysis
/// engine.
- GRStateManager &getStateManager();
+ ProgramStateManager &getStateManager();
virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
- llvm::SmallVectorImpl<BugReport*> &bugReports);
+ SmallVectorImpl<BugReport*> &bugReports);
void addNotableSymbol(SymbolRef Sym) {
NotableSymbols.insert(Sym);
@@ -413,20 +375,10 @@ public:
class BugReporterContext {
GRBugReporter &BR;
- // Not the most efficient data structure, but we use an ImmutableList for the
- // Callbacks because it is safe to make additions to list during iteration.
- llvm::ImmutableList<BugReporterVisitor*>::Factory F;
- llvm::ImmutableList<BugReporterVisitor*> Callbacks;
- llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
public:
- BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
- virtual ~BugReporterContext();
-
- void addVisitor(BugReporterVisitor* visitor);
+ BugReporterContext(GRBugReporter& br) : BR(br) {}
- typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
- visitor_iterator visitor_begin() { return Callbacks.begin(); }
- visitor_iterator visitor_end() { return Callbacks.end(); }
+ virtual ~BugReporterContext() {}
GRBugReporter& getBugReporter() { return BR; }
@@ -442,7 +394,7 @@ public:
return BR.isNotable(Sym);
}
- GRStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() {
return BR.getStateManager();
}
@@ -450,7 +402,7 @@ public:
return getStateManager().getSValBuilder();
}
- ASTContext& getASTContext() {
+ ASTContext &getASTContext() {
return BR.getContext();
}
@@ -461,50 +413,6 @@ public:
virtual BugReport::NodeResolver& getNodeResolver() = 0;
};
-class DiagBugReport : public RangedBugReport {
- std::list<std::string> Strs;
- FullSourceLoc L;
-public:
- DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
- RangedBugReport(D, desc, 0), L(l) {}
-
- virtual ~DiagBugReport() {}
-
- // FIXME: Move out-of-line (virtual function).
- SourceLocation getLocation() const { return L; }
-
- void addString(llvm::StringRef s) { Strs.push_back(s); }
-
- typedef std::list<std::string>::const_iterator str_iterator;
- str_iterator str_begin() const { return Strs.begin(); }
- str_iterator str_end() const { return Strs.end(); }
-};
-
-//===----------------------------------------------------------------------===//
-//===----------------------------------------------------------------------===//
-
-namespace bugreporter {
-
-const Stmt *GetDerefExpr(const ExplodedNode *N);
-const Stmt *GetDenomExpr(const ExplodedNode *N);
-const Stmt *GetCalleeExpr(const ExplodedNode *N);
-const Stmt *GetRetValExpr(const ExplodedNode *N);
-
-void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
- const ExplodedNode* N);
-
-void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
- const ExplodedNode *N);
-
-void registerNilReceiverVisitor(BugReporterContext &BRC);
-
-void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
- const ExplodedNode *N);
-
-} // end namespace clang::bugreporter
-
-//===----------------------------------------------------------------------===//
-
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
new file mode 100644
index 000000000000..41c0a3a46b1c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -0,0 +1,183 @@
+//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares BugReporterVisitors, which are used to generate enhanced
+// diagnostic traces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR
+#define LLVM_CLANG_GR_BUGREPORTERVISITOR
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+
+namespace ento {
+
+class BugReport;
+class BugReporterContext;
+class ExplodedNode;
+class MemRegion;
+class PathDiagnosticPiece;
+
+class BugReporterVisitor : public llvm::FoldingSetNode {
+public:
+ virtual ~BugReporterVisitor();
+
+ /// \brief Return a diagnostic piece which should be associated with the
+ /// given node.
+ ///
+ /// The last parameter can be used to register a new visitor with the given
+ /// BugReport while processing a node.
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) = 0;
+
+ /// \brief Provide custom definition for the final diagnostic piece on the
+ /// path - the piece, which is displayed before the path is expanded.
+ ///
+ /// If returns NULL the default implementation will be used.
+ /// Also note that at most one visitor of a BugReport should generate a
+ /// non-NULL end of path diagnostic piece.
+ virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ /// \brief Generates the default final diagnostic piece.
+ static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+};
+
+class FindLastStoreBRVisitor : public BugReporterVisitor {
+ const MemRegion *R;
+ SVal V;
+ bool satisfied;
+ const ExplodedNode *StoreSite;
+
+public:
+ /// \brief Convenience method to create a visitor given only the MemRegion.
+ /// Returns NULL if the visitor cannot be created. For example, when the
+ /// corresponding value is unknown.
+ static BugReporterVisitor *createVisitorObject(const ExplodedNode *N,
+ const MemRegion *R);
+
+ /// Creates a visitor for every VarDecl inside a Stmt and registers it with
+ /// the BugReport.
+ static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
+
+ FindLastStoreBRVisitor(SVal v, const MemRegion *r)
+ : R(r), V(v), satisfied(false), StoreSite(0) {
+ assert (!V.isUnknown() && "Cannot track unknown value.");
+
+ // TODO: Does it make sense to allow undef values here?
+ // (If not, also see UndefCapturedBlockVarChecker)?
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+class TrackConstraintBRVisitor : public BugReporterVisitor {
+ DefinedSVal Constraint;
+ const bool Assumption;
+ bool isSatisfied;
+
+public:
+ TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
+ : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+class NilReceiverBRVisitor : public BugReporterVisitor {
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
+/// Visitor that tries to report interesting diagnostics from conditions.
+class ConditionBRVisitor : public BugReporterVisitor {
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int x = 0;
+ ID.AddPointer(&x);
+ }
+
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR);
+
+ PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
+ const ExplodedNode *N,
+ const CFGBlock *srcBlk,
+ const CFGBlock *dstBlk,
+ BugReporterContext &BRC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ const DeclRefExpr *DR,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
+ const BinaryOperator *BExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC);
+
+ bool patternMatch(const Expr *Ex,
+ llvm::raw_ostream &Out,
+ BugReporterContext &BRC);
+};
+
+namespace bugreporter {
+
+BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
+ const Stmt *S);
+
+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
+} // end namespace ento
+} // end namespace bugreporter
+
+
+#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 7b9bb03d8d05..78067cd61c1e 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
@@ -22,6 +21,7 @@ namespace clang {
namespace ento {
+class BugReporter;
class ExplodedNode;
class ExprEngine;
@@ -31,13 +31,13 @@ private:
const std::string Category;
bool SuppressonSink;
public:
- BugType(llvm::StringRef name, llvm::StringRef cat)
+ BugType(StringRef name, StringRef cat)
: Name(name), Category(cat), SuppressonSink(false) {}
virtual ~BugType();
// FIXME: Should these be made strings as well?
- llvm::StringRef getName() const { return Name; }
- llvm::StringRef getCategory() const { return Category; }
+ StringRef getName() const { return Name; }
+ StringRef getCategory() const { return Category; }
/// isSuppressOnSink - Returns true if bug reports associated with this bug
/// type should be suppressed if the end node of the report is post-dominated
@@ -57,7 +57,7 @@ public:
BuiltinBug(const char *name)
: BugType(name, "Logic error"), desc(name) {}
- llvm::StringRef getDescription() const { return desc; }
+ StringRef getDescription() const { return desc; }
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 6d53c097d29f..406be3cc4bd4 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
#include <deque>
#include <iterator>
#include <string>
@@ -23,42 +24,55 @@
namespace clang {
+class AnalysisContext;
+class BinaryOperator;
+class CompoundStmt;
class Decl;
+class LocationContext;
+class MemberExpr;
+class ParentMap;
+class ProgramPoint;
class SourceManager;
class Stmt;
namespace ento {
+class ExplodedNode;
+
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
class PathDiagnostic;
-class PathDiagnosticClient : public DiagnosticClient {
+class PathDiagnosticConsumer {
public:
- PathDiagnosticClient() {}
+ PathDiagnosticConsumer() {}
- virtual ~PathDiagnosticClient() {}
+ virtual ~PathDiagnosticConsumer() {}
virtual void
- FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0;
+ FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
- void FlushDiagnostics(llvm::SmallVectorImpl<std::string> &FilesMade) {
+ void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
FlushDiagnostics(&FilesMade);
}
- virtual llvm::StringRef getName() const = 0;
+ virtual StringRef getName() const = 0;
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
- virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
+ void HandlePathDiagnostic(const PathDiagnostic* D);
enum PathGenerationScheme { Minimal, Extensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
virtual bool useVerboseDescription() const { return true; }
+
+protected:
+ /// The actual logic for handling path diagnostics, as implemented
+ /// by subclasses of PathDiagnosticConsumer.
+ virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
+
};
//===----------------------------------------------------------------------===//
@@ -67,60 +81,143 @@ public:
class PathDiagnosticRange : public SourceRange {
public:
- const bool isPoint;
+ bool isPoint;
PathDiagnosticRange(const SourceRange &R, bool isP = false)
: SourceRange(R), isPoint(isP) {}
+
+ PathDiagnosticRange() : isPoint(false) {}
};
+typedef llvm::PointerUnion<const LocationContext*, AnalysisContext*>
+ LocationOrAnalysisContext;
+
class PathDiagnosticLocation {
private:
enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
- SourceRange R;
const Stmt *S;
const Decl *D;
const SourceManager *SM;
+ FullSourceLoc Loc;
+ PathDiagnosticRange Range;
+
+ PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
+ Kind kind)
+ : K(kind), S(0), D(0), SM(&sm),
+ Loc(genLocation(L)), Range(genRange()) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
+
+ FullSourceLoc
+ genLocation(SourceLocation L = SourceLocation(),
+ LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+
+ PathDiagnosticRange
+ genRange(LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+
public:
+ /// Create an invalid location.
PathDiagnosticLocation()
: K(SingleLocK), S(0), D(0), SM(0) {}
- PathDiagnosticLocation(FullSourceLoc L)
- : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
+ /// Create a location corresponding to the given statement.
+ PathDiagnosticLocation(const Stmt *s,
+ const SourceManager &sm,
+ LocationOrAnalysisContext lac)
+ : K(StmtK), S(s), D(0), SM(&sm),
+ Loc(genLocation(SourceLocation(), lac)),
+ Range(genRange(lac)) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
- PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
- : K(StmtK), S(s), D(0), SM(&sm) {}
+ /// Create a location corresponding to the given declaration.
+ PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
+ : K(DeclK), S(0), D(d), SM(&sm),
+ Loc(genLocation()), Range(genRange()) {
+ assert(Loc.isValid());
+ assert(Range.isValid());
+ }
- PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
- : K(RangeK), R(r), S(0), D(0), SM(&sm) {}
+ /// Create a location corresponding to the given declaration.
+ static PathDiagnosticLocation create(const Decl *D,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(D, SM);
+ }
- PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
- : K(DeclK), S(0), D(d), SM(&sm) {}
+ /// Create a location for the beginning of the declaration.
+ static PathDiagnosticLocation createBegin(const Decl *D,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the statement.
+ static PathDiagnosticLocation createBegin(const Stmt *S,
+ const SourceManager &SM,
+ const LocationOrAnalysisContext LAC);
+
+ /// Create the location for the operator of the binary expression.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
+ const SourceManager &SM);
+
+ /// For member expressions, return the location of the '.' or '->'.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the compound statement.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
+ const SourceManager &SM);
+
+ /// Create a location for the end of the compound statement.
+ /// Assumes the statement has a valid location.
+ static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
+ const SourceManager &SM);
+
+ /// Create a location for the beginning of the enclosing declaration body.
+ /// Defaults to the beginning of the first statement in the declaration body.
+ static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
+ const SourceManager &SM);
+
+ /// Constructs a location for the end of the enclosing declaration body.
+ /// Defaults to the end of brace.
+ static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
+ const SourceManager &SM);
+
+ /// Create a location corresponding to the given valid ExplodedNode.
+ static PathDiagnosticLocation create(const ProgramPoint& P,
+ const SourceManager &SMng);
+
+ /// Create a location corresponding to the next valid ExplodedNode as end
+ /// of path location.
+ static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
+ const SourceManager &SM);
+
+ /// Convert the given location into a single kind location.
+ static PathDiagnosticLocation createSingleLocation(
+ const PathDiagnosticLocation &PDL);
bool operator==(const PathDiagnosticLocation &X) const {
- return K == X.K && R == X.R && S == X.S && D == X.D;
+ return K == X.K && Loc == X.Loc && Range == X.Range;
}
bool operator!=(const PathDiagnosticLocation &X) const {
- return K != X.K || R != X.R || S != X.S || D != X.D;;
- }
-
- PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) {
- K = X.K;
- R = X.R;
- S = X.S;
- D = X.D;
- SM = X.SM;
- return *this;
+ return !(*this == X);
}
bool isValid() const {
return SM != 0;
}
- const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
+ FullSourceLoc asLocation() const {
+ return Loc;
+ }
+
+ PathDiagnosticRange asRange() const {
+ return Range;
+ }
- FullSourceLoc asLocation() const;
- PathDiagnosticRange asRange() const;
const Stmt *asStmt() const { assert(isValid()); return S; }
const Decl *asDecl() const { assert(isValid()); return D; }
@@ -181,7 +278,7 @@ private:
PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
protected:
- PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below);
+ PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
@@ -191,7 +288,7 @@ public:
const std::string& getString() const { return str; }
/// getDisplayHint - Return a hint indicating where the diagnostic should
- /// be displayed by the PathDiagnosticClient.
+ /// be displayed by the PathDiagnosticConsumer.
DisplayHint getDisplayHint() const { return Hint; }
virtual PathDiagnosticLocation getLocation() const = 0;
@@ -199,9 +296,15 @@ public:
Kind getKind() const { return kind; }
- void addRange(SourceRange R) { ranges.push_back(R); }
+ void addRange(SourceRange R) {
+ if (!R.isValid())
+ return;
+ ranges.push_back(R);
+ }
void addRange(SourceLocation B, SourceLocation E) {
+ if (!B.isValid() || !E.isValid())
+ return;
ranges.push_back(SourceRange(B,E));
}
@@ -230,7 +333,7 @@ public:
: &FixItHints[0] + FixItHints.size();
}
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return true;
}
@@ -242,11 +345,11 @@ private:
PathDiagnosticLocation Pos;
public:
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
- llvm::StringRef s,
+ StringRef s,
PathDiagnosticPiece::Kind k,
bool addPosRange = true)
: PathDiagnosticPiece(s, k), Pos(pos) {
- assert(Pos.asLocation().isValid() &&
+ assert(Pos.isValid() && Pos.asLocation().isValid() &&
"PathDiagnosticSpotPiece's must have a valid location.");
if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
}
@@ -261,12 +364,12 @@ class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
- llvm::StringRef s, bool addPosRange = true)
+ StringRef s, bool addPosRange = true)
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
~PathDiagnosticEventPiece();
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Event;
}
};
@@ -276,7 +379,7 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
public:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos,
- llvm::StringRef s)
+ StringRef s)
: PathDiagnosticPiece(s, ControlFlow) {
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
}
@@ -320,7 +423,7 @@ public:
const_iterator begin() const { return LPairs.begin(); }
const_iterator end() const { return LPairs.end(); }
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == ControlFlow;
}
@@ -337,7 +440,7 @@ public:
bool containsEvent() const;
- void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
+ void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
iterator begin() { return SubPieces.begin(); }
@@ -352,7 +455,7 @@ public:
const_iterator begin() const { return SubPieces.begin(); }
const_iterator end() const { return SubPieces.end(); }
- static inline bool classof(const PathDiagnosticPiece* P) {
+ static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Macro;
}
@@ -373,42 +476,42 @@ class PathDiagnostic : public llvm::FoldingSetNode {
public:
PathDiagnostic();
- PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
- llvm::StringRef category);
+ PathDiagnostic(StringRef bugtype, StringRef desc,
+ StringRef category);
~PathDiagnostic();
- llvm::StringRef getDescription() const { return Desc; }
- llvm::StringRef getBugType() const { return BugType; }
- llvm::StringRef getCategory() const { return Category; }
+ StringRef getDescription() const { return Desc; }
+ StringRef getBugType() const { return BugType; }
+ StringRef getCategory() const { return Category; }
typedef std::deque<std::string>::const_iterator meta_iterator;
meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_iterator meta_end() const { return OtherDesc.end(); }
- void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); }
+ void addMeta(StringRef s) { OtherDesc.push_back(s); }
PathDiagnosticLocation getLocation() const {
assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
return rbegin()->getLocation();
}
- void push_front(PathDiagnosticPiece* piece) {
+ void push_front(PathDiagnosticPiece *piece) {
assert(piece);
path.push_front(piece);
++Size;
}
- void push_back(PathDiagnosticPiece* piece) {
+ void push_back(PathDiagnosticPiece *piece) {
assert(piece);
path.push_back(piece);
++Size;
}
- PathDiagnosticPiece* back() {
+ PathDiagnosticPiece *back() {
return path.back();
}
- const PathDiagnosticPiece* back() const {
+ const PathDiagnosticPiece *back() const {
return path.back();
}
@@ -433,14 +536,14 @@ public:
public:
iterator(const ImplTy& i) : I(i) {}
- bool operator==(const iterator& X) const { return I == X.I; }
- bool operator!=(const iterator& X) const { return I != X.I; }
+ bool operator==(const iterator &X) const { return I == X.I; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
PathDiagnosticPiece& operator*() const { return **I; }
- PathDiagnosticPiece* operator->() const { return *I; }
+ PathDiagnosticPiece *operator->() const { return *I; }
- iterator& operator++() { ++I; return *this; }
- iterator& operator--() { --I; return *this; }
+ iterator &operator++() { ++I; return *this; }
+ iterator &operator--() { --I; return *this; }
};
class const_iterator {
@@ -459,14 +562,14 @@ public:
public:
const_iterator(const ImplTy& i) : I(i) {}
- bool operator==(const const_iterator& X) const { return I == X.I; }
- bool operator!=(const const_iterator& X) const { return I != X.I; }
+ bool operator==(const const_iterator &X) const { return I == X.I; }
+ bool operator!=(const const_iterator &X) const { return I != X.I; }
reference operator*() const { return **I; }
pointer operator->() const { return *I; }
- const_iterator& operator++() { ++I; return *this; }
- const_iterator& operator--() { --I; return *this; }
+ const_iterator &operator++() { ++I; return *this; }
+ const_iterator &operator--() { --I; return *this; }
};
typedef std::reverse_iterator<iterator> reverse_iterator;
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index eb38bd8951e9..1e4edeb0c7ae 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_SA_CORE_CHECKER
#define LLVM_CLANG_SA_CORE_CHECKER
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/Support/Casting.h"
@@ -151,9 +152,10 @@ public:
class Location {
template <typename CHECKER>
- static void _checkLocation(void *checker, const SVal &location, bool isLoad,
+ static void _checkLocation(void *checker,
+ const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &C) {
- ((const CHECKER *)checker)->checkLocation(location, isLoad, C);
+ ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
}
public:
@@ -166,9 +168,10 @@ public:
class Bind {
template <typename CHECKER>
- static void _checkBind(void *checker, const SVal &location, const SVal &val,
+ static void _checkBind(void *checker,
+ const SVal &location, const SVal &val, const Stmt *S,
CheckerContext &C) {
- ((const CHECKER *)checker)->checkBind(location, val, C);
+ ((const CHECKER *)checker)->checkBind(location, val, S, C);
}
public:
@@ -227,7 +230,7 @@ public:
class LiveSymbols {
template <typename CHECKER>
- static void _checkLiveSymbols(void *checker, const GRState *state,
+ static void _checkLiveSymbols(void *checker, const ProgramState *state,
SymbolReaper &SR) {
((const CHECKER *)checker)->checkLiveSymbols(state, SR);
}
@@ -257,15 +260,18 @@ public:
class RegionChanges {
template <typename CHECKER>
- static const GRState *_checkRegionChanges(void *checker, const GRState *state,
- const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
+ static const ProgramState *
+ _checkRegionChanges(void *checker,
+ const ProgramState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> Explicits,
+ ArrayRef<const MemRegion *> Regions) {
return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
- Begin, End);
+ Explicits, Regions);
}
template <typename CHECKER>
- static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
+ static bool _wantsRegionChangeUpdate(void *checker,
+ const ProgramState *state) {
return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state);
}
@@ -300,8 +306,10 @@ namespace eval {
class Assume {
template <typename CHECKER>
- static const GRState *_evalAssume(void *checker, const GRState *state,
- const SVal &cond, bool assumption) {
+ static const ProgramState *_evalAssume(void *checker,
+ const ProgramState *state,
+ const SVal &cond,
+ bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
}
@@ -327,38 +335,73 @@ public:
}
};
+class InlineCall {
+ template <typename CHECKER>
+ static bool _inlineCall(void *checker, const CallExpr *CE,
+ ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForInlineCall(
+ CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>));
+ }
+};
+
} // end eval namespace
+class CheckerBase : public ProgramPointTag {
+public:
+ StringRef getTagDescription() const;
+
+ /// See CheckerManager::runCheckersForPrintState.
+ virtual void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) const { }
+};
+
template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck,
typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
- typename CHECK11=check::_VoidCheck,typename CHECK12=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>
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,
+ check::_VoidCheck>
+ : public CheckerBase
+{
public:
static void _register(void *checker, CheckerManager &mgr) { }
};
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 CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
+ typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16>
class Checker
: public CHECK1,
public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
- CHECK9, CHECK10, CHECK11, CHECK12> {
+ CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
+ CHECK16> {
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>::_register(checker, mgr);
+ Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
+ CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
+ CHECK16>::_register(checker, mgr);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 45d38fba0495..e3e4c49f71e1 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -27,6 +27,7 @@ namespace clang {
class CallExpr;
namespace ento {
+ class CheckerBase;
class ExprEngine;
class AnalysisManager;
class BugReporter;
@@ -36,7 +37,7 @@ namespace ento {
class ExplodedNode;
class ExplodedNodeSet;
class ExplodedGraph;
- class GRState;
+ class ProgramState;
class EndOfFunctionNodeBuilder;
class BranchNodeBuilder;
class MemRegion;
@@ -55,8 +56,8 @@ class CheckerFn<RET(P1, P2, P3, P4)> {
typedef RET (*Func)(void *, P1, P2, P3, P4);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const {
return Fn(Checker, p1, p2, p3, p4);
}
@@ -67,8 +68,8 @@ class CheckerFn<RET(P1, P2, P3)> {
typedef RET (*Func)(void *, P1, P2, P3);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); }
};
@@ -77,8 +78,8 @@ class CheckerFn<RET(P1, P2)> {
typedef RET (*Func)(void *, P1, P2);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); }
};
@@ -87,8 +88,8 @@ class CheckerFn<RET(P1)> {
typedef RET (*Func)(void *, P1);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()(P1 p1) const { return Fn(Checker, p1); }
};
@@ -97,8 +98,8 @@ class CheckerFn<RET()> {
typedef RET (*Func)(void *);
Func Fn;
public:
- void *Checker;
- CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
RET operator()() const { return Fn(Checker); }
};
@@ -115,8 +116,8 @@ public:
const LangOptions &getLangOptions() const { return LangOpts; }
- typedef void *CheckerRef;
- typedef void *CheckerTag;
+ typedef CheckerBase *CheckerRef;
+ typedef const void *CheckerTag;
typedef CheckerFn<void ()> CheckerDtor;
//===----------------------------------------------------------------------===//
@@ -157,6 +158,11 @@ public:
//===----------------------------------------------------------------------===//
/// \brief Run checkers for pre-visiting Stmts.
+ ///
+ /// The notification is performed for every explored CFGElement, which does
+ /// not include the control flow statements such as IfStmt.
+ ///
+ /// \sa runCheckersForBranchCondition, runCheckersForPostStmt
void runCheckersForPreStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
@@ -165,6 +171,11 @@ public:
}
/// \brief Run checkers for post-visiting Stmts.
+ ///
+ /// The notification is performed for every explored CFGElement, which does
+ /// not include the control flow statements such as IfStmt.
+ ///
+ /// \sa runCheckersForBranchCondition, runCheckersForPreStmt
void runCheckersForPostStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
@@ -224,27 +235,43 @@ public:
BranchNodeBuilder &B, ExprEngine &Eng);
/// \brief Run checkers for live symbols.
- void runCheckersForLiveSymbols(const GRState *state,
+ ///
+ /// Allows modifying SymbolReaper object. For example, checkers can explicitly
+ /// register symbols of interest as live. These symbols will not be marked
+ /// dead and removed.
+ void runCheckersForLiveSymbols(const ProgramState *state,
SymbolReaper &SymReaper);
/// \brief Run checkers for dead symbols.
+ ///
+ /// Notifies checkers when symbols become dead. For example, this allows
+ /// checkers to aggressively clean up/reduce the checker state and produce
+ /// precise diagnostics.
void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SymbolReaper &SymReaper, const Stmt *S,
ExprEngine &Eng);
/// \brief True if at least one checker wants to check region changes.
- bool wantsRegionChangeUpdate(const GRState *state);
+ bool wantsRegionChangeUpdate(const ProgramState *state);
/// \brief Run checkers for region changes.
- const GRState *
- runCheckersForRegionChanges(const GRState *state,
+ ///
+ /// This corresponds to the check::RegionChanges callback.
+ /// \param state The current program state.
+ /// \param invalidated A set of all symbols potentially touched by the change.
+ /// \param ExplicitRegions The regions explicitly requested for invalidation.
+ /// 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.
+ const ProgramState *
+ runCheckersForRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions);
/// \brief Run checkers for handling assumptions on symbolic values.
- const GRState *runCheckersForEvalAssume(const GRState *state,
+ const ProgramState *runCheckersForEvalAssume(const ProgramState *state,
SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
@@ -254,10 +281,21 @@ public:
GraphExpander *defaultEval = 0);
/// \brief Run checkers for the entire Translation Unit.
- void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl* TU,
+ void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager &mgr,
BugReporter &BR);
+ /// \brief Run checkers for debug-printing a ProgramState.
+ ///
+ /// Unlike most other callbacks, any checker can simply implement the virtual
+ /// method CheckerBase::printState if it has custom data to print.
+ /// \param Out The output stream
+ /// \param State The state being printed
+ /// \param NL The preferred representation of a newline.
+ /// \param Sep The preferred separator between different kinds of data.
+ void runCheckersForPrintState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep);
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
@@ -282,11 +320,13 @@ public:
typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
CheckObjCMessageFunc;
- typedef CheckerFn<void (const SVal &location, bool isLoad, CheckerContext &)>
+ typedef CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
+ CheckerContext &)>
CheckLocationFunc;
- typedef CheckerFn<void (const SVal &location, const SVal &val,
- CheckerContext &)> CheckBindFunc;
+ typedef CheckerFn<void (const SVal &location, const SVal &val,
+ const Stmt *S, CheckerContext &)>
+ CheckBindFunc;
typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
CheckEndAnalysisFunc;
@@ -300,23 +340,28 @@ public:
typedef CheckerFn<void (SymbolReaper &, CheckerContext &)>
CheckDeadSymbolsFunc;
- typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc;
+ typedef CheckerFn<void (const ProgramState *,SymbolReaper &)> CheckLiveSymbolsFunc;
- typedef CheckerFn<const GRState * (const GRState *,
+ typedef CheckerFn<const ProgramState * (const ProgramState *,
const StoreManager::InvalidatedSymbols *symbols,
- const MemRegion * const *begin,
- const MemRegion * const *end)>
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions)>
CheckRegionChangesFunc;
- typedef CheckerFn<bool (const GRState *)> WantsRegionChangeUpdateFunc;
+ typedef CheckerFn<bool (const ProgramState *)> WantsRegionChangeUpdateFunc;
- typedef CheckerFn<const GRState * (const GRState *,
- const SVal &cond, bool assumption)>
+ typedef CheckerFn<const ProgramState * (const ProgramState *,
+ const SVal &cond, bool assumption)>
EvalAssumeFunc;
typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
EvalCallFunc;
+ typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst)>
+ InlineCallFunc;
+
typedef CheckerFn<void (const TranslationUnitDecl *,
AnalysisManager&, BugReporter &)>
CheckEndOfTranslationUnit;
@@ -351,6 +396,8 @@ public:
void _registerForEvalCall(EvalCallFunc checkfn);
+ void _registerForInlineCall(InlineCallFunc checkfn);
+
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
//===----------------------------------------------------------------------===//
@@ -405,7 +452,7 @@ private:
std::vector<CheckDeclFunc> BodyCheckers;
- typedef llvm::SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
+ typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
CachedDeclCheckersMapTy CachedDeclCheckersMap;
@@ -439,7 +486,7 @@ private:
};
friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>;
- typedef llvm::SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
+ typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers>
CachedStmtCheckersMapTy;
CachedStmtCheckersMapTy CachedStmtCheckersMap;
@@ -473,10 +520,12 @@ private:
std::vector<EvalCallFunc> EvalCallCheckers;
+ std::vector<InlineCallFunc> InlineCallCheckers;
+
std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
struct EventInfo {
- llvm::SmallVector<CheckEventFunc, 4> Checkers;
+ SmallVector<CheckEventFunc, 4> Checkers;
bool HasDispatcher;
EventInfo() : HasDispatcher(false) { }
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
new file mode 100644
index 000000000000..6ce5b3c5095e
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
@@ -0,0 +1,43 @@
+//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- 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_STATICANALYZER_CORE_CHECKEROPTINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+namespace ento {
+
+/// Represents a request to include or exclude a checker or package from a
+/// specific analysis run.
+///
+/// \sa CheckerRegistry::initializeManager
+class CheckerOptInfo {
+ StringRef Name;
+ bool Enable;
+ bool Claimed;
+
+public:
+ CheckerOptInfo(StringRef name, bool enable)
+ : Name(name), Enable(enable), Claimed(false) { }
+
+ StringRef getName() const { return Name; }
+ bool isEnabled() const { return Enable; }
+ bool isDisabled() const { return !isEnabled(); }
+
+ bool isClaimed() const { return Claimed; }
+ bool isUnclaimed() const { return !isClaimed(); }
+ void claim() { Claimed = true; }
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
deleted file mode 100644
index b8aaaa1a04c0..000000000000
--- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===--- CheckerProvider.h - Static Analyzer Checkers Provider --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the Static Analyzer Checker Provider.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
-#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
-
-#include "llvm/ADT/StringRef.h"
-
-namespace llvm {
- class raw_ostream;
-}
-
-namespace clang {
-
-namespace ento {
- class CheckerManager;
-
-class CheckerOptInfo {
- const char *Name;
- bool Enable;
- bool Claimed;
-
-public:
- CheckerOptInfo(const char *name, bool enable)
- : Name(name), Enable(enable), Claimed(false) { }
-
- const char *getName() const { return Name; }
- bool isEnabled() const { return Enable; }
- bool isDisabled() const { return !isEnabled(); }
-
- bool isClaimed() const { return Claimed; }
- bool isUnclaimed() const { return !isClaimed(); }
- void claim() { Claimed = true; }
-};
-
-class CheckerProvider {
-public:
- virtual ~CheckerProvider();
- virtual void registerCheckers(CheckerManager &checkerMgr,
- CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0;
- virtual void printHelp(llvm::raw_ostream &OS) = 0;
-};
-
-} // end ento namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
new file mode 100644
index 000000000000..b59c14d32f91
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -0,0 +1,132 @@
+//===--- CheckerRegistry.h - Maintains all available checkers ---*- 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_STATICANALYZER_CORE_CHECKERREGISTRY_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/Basic/LLVM.h"
+#include <vector>
+
+// FIXME: move this information to an HTML file in docs/.
+// At the very least, a checker plugin is a dynamic library that exports
+// clang_analyzerAPIVersionString. This should be defined as follows:
+//
+// extern "C"
+// const char clang_analyzerAPIVersionString[] =
+// CLANG_ANALYZER_API_VERSION_STRING;
+//
+// This is used to check whether the current version of the analyzer is known to
+// be incompatible with a plugin. Plugins with incompatible version strings,
+// or without a version string at all, will not be loaded.
+//
+// To add a custom checker to the analyzer, the plugin must also define the
+// function clang_registerCheckers. For example:
+//
+// extern "C"
+// void clang_registerCheckers (CheckerRegistry &registry) {
+// registry.addChecker<MainCallChecker>("example.MainCallChecker",
+// "Disallows calls to functions called main");
+// }
+//
+// The first method argument is the full name of the checker, including its
+// enclosing package. By convention, the registered name of a checker is the
+// name of the associated class (the template argument).
+// The second method argument is a short human-readable description of the
+// checker.
+//
+// The clang_registerCheckers function may add any number of checkers to the
+// registry. If any checkers require additional initialization, use the three-
+// argument form of CheckerRegistry::addChecker.
+//
+// To load a checker plugin, specify the full path to the dynamic library as
+// the argument to the -load option in the cc1 frontend. You can then enable
+// your custom checker using the -analyzer-checker:
+//
+// clang -cc1 -load </path/to/plugin.dylib> -analyze
+// -analyzer-checker=<example.MainCallChecker>
+//
+// For a complete working example, see examples/analyzer-plugin.
+
+
+namespace clang {
+namespace ento {
+
+#ifndef CLANG_ANALYZER_API_VERSION_STRING
+// FIXME: The Clang version string is not particularly granular;
+// the analyzer infrastructure can change a lot between releases.
+// Unfortunately, this string has to be statically embedded in each plugin,
+// so we can't just use the functions defined in Version.h.
+#include "clang/Basic/Version.h"
+#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING
+#endif
+
+class CheckerOptInfo;
+
+/// Manages a set of available checkers for running a static analysis.
+/// The checkers are organized into packages by full name, where including
+/// a package will recursively include all subpackages and checkers within it.
+/// For example, the checker "core.builtin.NoReturnFunctionChecker" will be
+/// included if initializeManager() is called with an option of "core",
+/// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker".
+class CheckerRegistry {
+public:
+ /// Initialization functions perform any necessary setup for a checker.
+ /// They should include a call to CheckerManager::registerChecker.
+ typedef void (*InitializationFunction)(CheckerManager &);
+ struct CheckerInfo {
+ InitializationFunction Initialize;
+ StringRef FullName;
+ StringRef Desc;
+
+ CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc)
+ : Initialize(fn), FullName(name), Desc(desc) {}
+ };
+
+ typedef std::vector<CheckerInfo> CheckerInfoList;
+
+private:
+ template <typename T>
+ static void initializeManager(CheckerManager &mgr) {
+ mgr.registerChecker<T>();
+ }
+
+public:
+ /// Adds a checker to the registry. Use this non-templated overload when your
+ /// checker requires custom initialization.
+ void addChecker(InitializationFunction fn, StringRef fullName,
+ StringRef desc);
+
+ /// Adds a checker to the registry. Use this templated overload when your
+ /// checker does not require any custom initialization.
+ template <class T>
+ void addChecker(StringRef fullName, StringRef desc) {
+ addChecker(&initializeManager<T>, fullName, desc);
+ }
+
+ /// Initializes a CheckerManager by calling the initialization functions for
+ /// all checkers specified by the given CheckerOptInfo list. The order of this
+ /// list is significant; later options can be used to reverse earlier ones.
+ /// This can be used to exclude certain checkers in an included package.
+ void initializeManager(CheckerManager &mgr,
+ SmallVectorImpl<CheckerOptInfo> &opts) const;
+
+ /// Prints the name and description of all checkers in this registry.
+ /// This output is not intended to be machine-parseable.
+ void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ;
+
+private:
+ mutable CheckerInfoList Checkers;
+ mutable llvm::StringMap<size_t> Packages;
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index d02228fa30dd..d1f5a7da5599 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -22,18 +22,18 @@ class Preprocessor;
namespace ento {
-class PathDiagnosticClient;
+class PathDiagnosticConsumer;
-PathDiagnosticClient*
-createHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP);
+PathDiagnosticConsumer*
+createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP);
-PathDiagnosticClient*
-createPlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP,
- PathDiagnosticClient *SubPD = 0);
+PathDiagnosticConsumer*
+createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP,
+ PathDiagnosticConsumer *SubPD = 0);
-PathDiagnosticClient*
-createTextPathDiagnosticClient(const std::string& prefix,
- const Preprocessor &PP);
+PathDiagnosticConsumer*
+createTextPathDiagnosticConsumer(const std::string& prefix,
+ const Preprocessor &PP);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 1ba038e6da2d..6c93f59d2094 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Frontend/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
@@ -34,10 +35,10 @@ class AnalysisManager : public BugReporterData {
LocationContextManager LocCtxMgr;
ASTContext &Ctx;
- Diagnostic &Diags;
+ DiagnosticsEngine &Diags;
const LangOptions &LangInfo;
- llvm::OwningPtr<PathDiagnosticClient> PD;
+ llvm::OwningPtr<PathDiagnosticConsumer> PD;
// Configurable components creators.
StoreManagerCreator CreateStoreMgr;
@@ -60,7 +61,7 @@ class AnalysisManager : public BugReporterData {
bool VisualizeEGDot;
bool VisualizeEGUbi;
- bool PurgeDead;
+ AnalysisPurgeMode PurgeDead;
/// EargerlyAssume - A flag indicating how the engine should handle
// expressions such as: 'x = (y != 0)'. When this flag is true then
@@ -75,27 +76,24 @@ class AnalysisManager : public BugReporterData {
bool EagerlyTrimEGraph;
public:
- AnalysisManager(ASTContext &ctx, Diagnostic &diags,
- const LangOptions &lang, PathDiagnosticClient *pd,
+ AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ const LangOptions &lang, PathDiagnosticConsumer *pd,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
idx::Indexer *idxer,
unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
+ bool vizdot, bool vizubi, AnalysisPurgeMode purge,
+ bool eager, bool trim,
bool inlinecall, bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
- bool eagerlyTrimEGraph)
-
- : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
- Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
- CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- CheckerMgr(checkerMgr), Idxer(idxer),
- AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
- VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall),
- EagerlyTrimEGraph(eagerlyTrimEGraph) {}
-
+ bool eagerlyTrimEGraph);
+
+ /// Construct a clone of the given AnalysisManager with the given ASTContext
+ /// and DiagnosticsEngine.
+ AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ AnalysisManager &ParentAM);
+
~AnalysisManager() { FlushDiagnostics(); }
void ClearContexts() {
@@ -127,7 +125,7 @@ public:
return getASTContext().getSourceManager();
}
- virtual Diagnostic &getDiagnostic() {
+ virtual DiagnosticsEngine &getDiagnostic() {
return Diags;
}
@@ -135,7 +133,7 @@ public:
return LangInfo;
}
- virtual PathDiagnosticClient *getPathDiagnosticClient() {
+ virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() {
return PD.get();
}
@@ -160,7 +158,7 @@ public:
bool shouldTrimGraph() const { return TrimGraph; }
- bool shouldPurgeDead() const { return PurgeDead; }
+ AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }
bool shouldEagerlyAssume() const { return EagerlyAssume; }
@@ -174,8 +172,9 @@ public:
return AnaCtxMgr.getContext(D)->getCFG();
}
- LiveVariables *getLiveVariables(Decl const *D) {
- return AnaCtxMgr.getContext(D)->getLiveVariables();
+ template <typename T>
+ T *getAnalysis(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getAnalysis<T>();
}
ParentMap &getParentMap(Decl const *D) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 69495be400a3..42a15370a427 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -27,7 +27,7 @@ namespace clang {
namespace ento {
- class GRState;
+class ProgramState;
class CompoundValData : public llvm::FoldingSetNode {
QualType T;
@@ -49,17 +49,17 @@ public:
class LazyCompoundValData : public llvm::FoldingSetNode {
StoreRef store;
- const TypedRegion *region;
+ const TypedValueRegion *region;
public:
- LazyCompoundValData(const StoreRef &st, const TypedRegion *r)
+ LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
: store(st), region(r) {}
const void *getStore() const { return store.getStore(); }
- const TypedRegion *getRegion() const { return region; }
+ const TypedValueRegion *getRegion() const { return region; }
static void Profile(llvm::FoldingSetNodeID& ID,
const StoreRef &store,
- const TypedRegion *region);
+ const TypedValueRegion *region);
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
@@ -68,25 +68,25 @@ class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
- ASTContext& Ctx;
+ ASTContext &Ctx;
llvm::BumpPtrAllocator& BPAlloc;
APSIntSetTy APSIntSet;
- void* PersistentSVals;
- void* PersistentSValPairs;
+ void * PersistentSVals;
+ void * PersistentSValPairs;
llvm::ImmutableList<SVal>::Factory SValListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
public:
- BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+ BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
SValListFactory(Alloc) {}
~BasicValueFactory();
- ASTContext& getContext() const { return Ctx; }
+ ASTContext &getContext() const { return Ctx; }
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
@@ -176,7 +176,7 @@ public:
llvm::ImmutableList<SVal> Vals);
const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
- const TypedRegion *region);
+ const TypedValueRegion *region);
llvm::ImmutableList<SVal> getEmptySValList() {
return SValListFactory.getEmptyList();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
index 7d0fdfb5f11f..2483a79455b2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
@@ -26,10 +26,13 @@ class StackFrameContext;
namespace ento {
+/// \class BlockCounter
+/// \brief An abstract data type used to count the number of times a given
+/// block has been visited along a path analyzed by CoreEngine.
class BlockCounter {
- void* Data;
+ void *Data;
- BlockCounter(void* D) : Data(D) {}
+ BlockCounter(void *D) : Data(D) {}
public:
BlockCounter() : Data(0) {}
@@ -38,7 +41,7 @@ public:
unsigned BlockID) const;
class Factory {
- void* F;
+ void *F;
public:
Factory(llvm::BumpPtrAllocator& Alloc);
~Factory();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 4429c6b2a7ad..1f1478713260 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -28,26 +28,29 @@ class CheckerContext {
ExprEngine &Eng;
ExplodedNode *Pred;
SaveAndRestore<bool> OldSink;
- const void *checkerTag;
- SaveAndRestore<ProgramPoint::Kind> OldPointKind;
SaveOr OldHasGen;
- const GRState *ST;
- const Stmt *statement;
+ const ProgramPoint Location;
+ const ProgramState *ST;
const unsigned size;
public:
bool *respondsToCallback;
public:
- CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
- ExprEngine &eng, ExplodedNode *pred,
- const void *tag, ProgramPoint::Kind K,
+ CheckerContext(ExplodedNodeSet &dst,
+ StmtNodeBuilder &builder,
+ ExprEngine &eng,
+ ExplodedNode *pred,
+ const ProgramPoint &loc,
bool *respondsToCB = 0,
- const Stmt *stmt = 0, const GRState *st = 0)
- : Dst(dst), B(builder), Eng(eng), Pred(pred),
+ const ProgramState *st = 0)
+ : Dst(dst),
+ B(builder),
+ Eng(eng),
+ Pred(pred),
OldSink(B.BuildSinks),
- checkerTag(tag),
- OldPointKind(B.PointKind, K),
OldHasGen(B.hasGeneratedNode),
- ST(st), statement(stmt), size(Dst.size()),
+ Location(loc),
+ ST(st),
+ size(Dst.size()),
respondsToCallback(respondsToCB) {}
~CheckerContext();
@@ -69,10 +72,12 @@ public:
}
ExplodedNodeSet &getNodeSet() { return Dst; }
- StmtNodeBuilder &getNodeBuilder() { return B; }
ExplodedNode *&getPredecessor() { return Pred; }
- const GRState *getState() { return ST ? ST : B.GetState(Pred); }
- const Stmt *getStmt() const { return statement; }
+ const ProgramState *getState() { return ST ? ST : Pred->getState(); }
+
+ /// \brief Returns the number of times the current block has been visited
+ /// along the analyzed path.
+ unsigned getCurrentBlockCount() {return B.getCurrentBlockCount();}
ASTContext &getASTContext() {
return Eng.getContext();
@@ -90,64 +95,58 @@ public:
return Eng.getSValBuilder();
}
- ExplodedNode *generateNode(bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, getState(), false,
- checkerTag);
- if (N && autoTransition)
- Dst.Add(N);
- return N;
+ SymbolManager &getSymbolManager() {
+ return getSValBuilder().getSymbolManager();
}
-
- ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
- bool autoTransition = true, const void *tag = 0) {
- assert(state);
- ExplodedNode *N = generateNodeImpl(stmt, state, false,
- tag ? tag : checkerTag);
- if (N && autoTransition)
- addTransition(N);
- return N;
+
+ bool isObjCGCEnabled() {
+ return Eng.isObjCGCEnabled();
}
- ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
+ /// \brief Generate a default checker node (containing checker tag but no
+ /// checker state changes).
+ ExplodedNode *generateNode(bool autoTransition = true) {
+ return generateNode(getState(), autoTransition);
+ }
+
+ /// \brief Generate a new checker node with the given predecessor.
+ /// Allows checkers to generate a chain of nodes.
+ ExplodedNode *generateNode(const ProgramState *state,
+ ExplodedNode *pred,
+ const ProgramPointTag *tag = 0,
bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
+ ExplodedNode *N = generateNodeImpl(state, false, pred, tag);
if (N && autoTransition)
addTransition(N);
return N;
}
- ExplodedNode *generateNode(const GRState *state, bool autoTransition = true,
- const void *tag = 0) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, false,
- tag ? tag : checkerTag);
+ /// \brief Generate a new checker node.
+ ExplodedNode *generateNode(const ProgramState *state,
+ bool autoTransition = true,
+ const ProgramPointTag *tag = 0) {
+ ExplodedNode *N = generateNodeImpl(state, false, 0, tag);
if (N && autoTransition)
addTransition(N);
return N;
}
- ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
- return generateNodeImpl(stmt, state ? state : getState(), true,
- checkerTag);
- }
-
- ExplodedNode *generateSink(const GRState *state = 0) {
- assert(statement && "Only transitions with statements currently supported");
- return generateNodeImpl(statement, state ? state : getState(), true,
- checkerTag);
+ /// \brief Generate a sink node. Generating sink stops exploration of the
+ /// given path.
+ ExplodedNode *generateSink(const ProgramState *state = 0) {
+ return generateNodeImpl(state ? state : getState(), true);
}
void addTransition(ExplodedNode *node) {
Dst.Add(node);
}
- void addTransition(const GRState *state, const void *tag = 0) {
+ void addTransition(const ProgramState *state,
+ const ProgramPointTag *tag = 0) {
assert(state);
// If the 'state' is not new, we need to check if the cached state 'ST'
// is new.
- if (state != getState() || (ST && ST != B.GetState(Pred)))
+ if (state != getState() || (ST && ST != Pred->getState()))
// state is new or equals to ST.
generateNode(state, true, tag);
else
@@ -163,17 +162,14 @@ public:
}
private:
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- bool markAsSink, const void *tag) {
- ExplodedNode *node = B.generateNode(stmt, state, Pred, tag);
- if (markAsSink && node)
- node->markAsSink();
- return node;
- }
-
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- ExplodedNode *pred, bool markAsSink) {
- ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag);
+ ExplodedNode *generateNodeImpl(const ProgramState *state,
+ bool markAsSink,
+ ExplodedNode *pred = 0,
+ const ProgramPointTag *tag = 0) {
+
+ ExplodedNode *node = B.generateNode(tag ? Location.withTag(tag) : Location,
+ state,
+ pred ? pred : Pred);
if (markAsSink && node)
node->markAsSink();
return node;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 199b41afefae..3f6dddead8e9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
-// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace llvm {
class APSInt;
@@ -25,36 +25,40 @@ namespace clang {
namespace ento {
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class SubEngine;
-class SVal;
class ConstraintManager {
public:
virtual ~ConstraintManager();
- virtual const GRState *assume(const GRState *state, DefinedSVal Cond,
- bool Assumption) = 0;
+ virtual const ProgramState *assume(const ProgramState *state,
+ DefinedSVal Cond,
+ bool Assumption) = 0;
- std::pair<const GRState*, const GRState*> assumeDual(const GRState *state,
- DefinedSVal Cond) {
+ std::pair<const ProgramState*, const ProgramState*>
+ assumeDual(const ProgramState *state, DefinedSVal Cond)
+ {
return std::make_pair(assume(state, Cond, true),
assume(state, Cond, false));
}
- virtual const llvm::APSInt* getSymVal(const GRState *state,
+ virtual const llvm::APSInt* getSymVal(const ProgramState *state,
SymbolRef sym) const = 0;
- virtual bool isEqual(const GRState *state, SymbolRef sym,
+ virtual bool isEqual(const ProgramState *state,
+ SymbolRef sym,
const llvm::APSInt& V) const = 0;
- virtual const GRState *removeDeadBindings(const GRState *state,
- SymbolReaper& SymReaper) = 0;
+ virtual const ProgramState *removeDeadBindings(const ProgramState *state,
+ SymbolReaper& SymReaper) = 0;
- virtual void print(const GRState *state, llvm::raw_ostream& Out,
- const char* nl, const char *sep) = 0;
+ virtual void print(const ProgramState *state,
+ raw_ostream &Out,
+ const char* nl,
+ const char *sep) = 0;
- virtual void EndPath(const GRState *state) {}
+ virtual void EndPath(const ProgramState *state) {}
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
@@ -64,9 +68,9 @@ public:
virtual bool canReasonAbout(SVal X) const = 0;
};
-ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
+ConstraintManager* CreateBasicConstraintManager(ProgramStateManager& statemgr,
SubEngine &subengine);
-ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
+ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
SubEngine &subengine);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 2c1d07c59b68..131d39e75528 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -19,11 +19,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
+class ProgramPointTag;
+
namespace ento {
//===----------------------------------------------------------------------===//
@@ -77,16 +78,17 @@ private:
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
- void generateNode(const ProgramPoint& Loc, const GRState* State,
- ExplodedNode* Pred);
+ void generateNode(const ProgramPoint &Loc,
+ const ProgramState *State,
+ ExplodedNode *Pred);
- void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
- void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
- void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred);
- void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred);
+ void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
+ void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
+ void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
+ void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
- void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
- ExplodedNode* Pred);
+ void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
+ ExplodedNode *Pred);
void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred);
void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
@@ -124,9 +126,10 @@ public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
- const GRState *InitState);
- void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
- const GRState *InitState,
+ const ProgramState *InitState);
+ void ExecuteWorkListWithInitialState(const LocationContext *L,
+ unsigned Steps,
+ const ProgramState *InitState,
ExplodedNodeSet &Dst);
// Functions for external checking of whether we have unfinished work
@@ -160,41 +163,36 @@ public:
class StmtNodeBuilder {
CoreEngine& Eng;
- const CFGBlock& B;
+ const CFGBlock &B;
const unsigned Idx;
- ExplodedNode* Pred;
- GRStateManager& Mgr;
+ ExplodedNode *Pred;
+
public:
bool PurgingDeadSymbols;
bool BuildSinks;
bool hasGeneratedNode;
ProgramPoint::Kind PointKind;
- const void *Tag;
-
- const GRState* CleanedState;
-
+ const ProgramPointTag *Tag;
typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
DeferredTy Deferred;
- void GenerateAutoTransition(ExplodedNode* N);
+ void GenerateAutoTransition(ExplodedNode *N);
public:
- StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
- CoreEngine* e, GRStateManager &mgr);
+ StmtNodeBuilder(const CFGBlock *b,
+ unsigned idx,
+ ExplodedNode *N,
+ CoreEngine* e);
~StmtNodeBuilder();
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
// FIXME: This should not be exposed.
WorkList *getWorkList() { return Eng.WList; }
- void SetCleanedState(const GRState* St) {
- CleanedState = St;
- }
-
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
@@ -203,14 +201,11 @@ public:
B.getBlockID());
}
- ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
- hasGeneratedNode = true;
- return generateNodeInternal(PP, St, Pred);
- }
-
- ExplodedNode* generateNode(const Stmt *S, const GRState *St,
- ExplodedNode *Pred, ProgramPoint::Kind K,
- const void *tag = 0) {
+ ExplodedNode *generateNode(const Stmt *S,
+ const ProgramState *St,
+ ExplodedNode *Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag = 0) {
hasGeneratedNode = true;
if (PurgingDeadSymbols)
@@ -219,59 +214,65 @@ public:
return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
}
- ExplodedNode* generateNode(const Stmt *S, const GRState *St,
- ExplodedNode *Pred, const void *tag = 0) {
+ ExplodedNode *generateNode(const Stmt *S,
+ const ProgramState *St,
+ ExplodedNode *Pred,
+ const ProgramPointTag *tag = 0) {
return generateNode(S, St, Pred, PointKind, tag);
}
- ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
- ExplodedNode* Pred) {
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ const ProgramState *State,
+ ExplodedNode *Pred) {
hasGeneratedNode = true;
return generateNodeInternal(PP, State, Pred);
}
ExplodedNode*
- generateNodeInternal(const ProgramPoint &PP, const GRState* State,
- ExplodedNode* Pred);
+ generateNodeInternal(const ProgramPoint &PP,
+ const ProgramState *State,
+ ExplodedNode *Pred);
ExplodedNode*
- generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
- ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
- const void *tag = 0);
+ generateNodeInternal(const Stmt *S,
+ const ProgramState *State,
+ ExplodedNode *Pred,
+ ProgramPoint::Kind K,
+ const ProgramPointTag *tag = 0);
/// getStmt - Return the current block-level expression associated with
/// this builder.
- const Stmt* getStmt() const {
+ const Stmt *getStmt() const {
const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
return CS ? CS->getStmt() : 0;
}
/// getBlock - Return the CFGBlock associated with the block-level expression
/// of this builder.
- const CFGBlock* getBlock() const { return &B; }
+ const CFGBlock *getBlock() const { return &B; }
unsigned getIndex() const { return Idx; }
- const GRState* GetState(ExplodedNode* Pred) const {
- if (Pred == getPredecessor())
- return CleanedState;
- else
- return Pred->getState();
- }
-
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St) {
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St) {
return MakeNode(Dst, S, Pred, St, PointKind);
}
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
- const GRState* St, ProgramPoint::Kind K);
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St,
+ ProgramPoint::Kind K);
- ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St) {
+ ExplodedNode *MakeSinkNode(ExplodedNodeSet &Dst,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ const ProgramState *St) {
bool Tmp = BuildSinks;
BuildSinks = true;
- ExplodedNode* N = MakeNode(Dst, S, Pred, St);
+ ExplodedNode *N = MakeNode(Dst, S, Pred, St);
BuildSinks = Tmp;
return N;
}
@@ -279,12 +280,12 @@ public:
class BranchNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const CFGBlock* DstT;
- const CFGBlock* DstF;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const CFGBlock *DstT;
+ const CFGBlock *DstF;
+ ExplodedNode *Pred;
- typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
+ typedef SmallVector<ExplodedNode*,3> DeferredTy;
DeferredTy Deferred;
bool GeneratedTrue;
@@ -293,25 +294,27 @@ class BranchNodeBuilder {
bool InFeasibleFalse;
public:
- BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT,
- const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e)
+ BranchNodeBuilder(const CFGBlock *src, const CFGBlock *dstT,
+ const CFGBlock *dstF, ExplodedNode *pred, CoreEngine* e)
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
GeneratedTrue(false), GeneratedFalse(false),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
~BranchNodeBuilder();
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
const ExplodedGraph& getGraph() const { return *Eng.G; }
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
- ExplodedNode* generateNode(const Stmt *Condition, const GRState* State);
+ /// This function generates a new ExplodedNode but not a new
+ /// branch(block edge).
+ ExplodedNode *generateNode(const Stmt *Condition, const ProgramState *State);
- ExplodedNode* generateNode(const GRState* State, bool branch);
+ ExplodedNode *generateNode(const ProgramState *State, bool branch);
- const CFGBlock* getTargetBlock(bool branch) const {
+ const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}
@@ -326,21 +329,21 @@ public:
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
- const GRState* getState() const {
+ const ProgramState *getState() const {
return getPredecessor()->getState();
}
};
class IndirectGotoNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const CFGBlock& DispatchBlock;
- const Expr* E;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const CFGBlock &DispatchBlock;
+ const Expr *E;
+ ExplodedNode *Pred;
public:
- IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
- const Expr* e, const CFGBlock* dispatch, CoreEngine* eng)
+ IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
class iterator {
@@ -350,8 +353,8 @@ public:
iterator(CFGBlock::const_succ_iterator i) : I(i) {}
public:
- iterator& operator++() { ++I; return *this; }
- bool operator!=(const iterator& X) const { return I != X.I; }
+ iterator &operator++() { ++I; return *this; }
+ bool operator!=(const iterator &X) const { return I != X.I; }
const LabelDecl *getLabel() const {
return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
@@ -365,23 +368,24 @@ public:
iterator begin() { return iterator(DispatchBlock.succ_begin()); }
iterator end() { return iterator(DispatchBlock.succ_end()); }
- ExplodedNode* generateNode(const iterator& I, const GRState* State,
+ ExplodedNode *generateNode(const iterator &I,
+ const ProgramState *State,
bool isSink = false);
- const Expr* getTarget() const { return E; }
+ const Expr *getTarget() const { return E; }
- const GRState* getState() const { return Pred->State; }
+ const ProgramState *getState() const { return Pred->State; }
};
class SwitchNodeBuilder {
CoreEngine& Eng;
- const CFGBlock* Src;
- const Expr* Condition;
- ExplodedNode* Pred;
+ const CFGBlock *Src;
+ const Expr *Condition;
+ ExplodedNode *Pred;
public:
- SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
- const Expr* condition, CoreEngine* eng)
+ SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
+ const Expr *condition, CoreEngine* eng)
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
class iterator {
@@ -391,15 +395,15 @@ public:
iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
public:
- iterator& operator++() { ++I; return *this; }
+ iterator &operator++() { ++I; return *this; }
bool operator!=(const iterator &X) const { return I != X.I; }
bool operator==(const iterator &X) const { return I == X.I; }
- const CaseStmt* getCase() const {
+ const CaseStmt *getCase() const {
return llvm::cast<CaseStmt>((*I)->getLabel());
}
- const CFGBlock* getBlock() const {
+ const CFGBlock *getBlock() const {
return *I;
}
};
@@ -411,14 +415,15 @@ public:
return llvm::cast<SwitchStmt>(Src->getTerminator());
}
- ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
+ ExplodedNode *generateCaseStmtNode(const iterator &I,
+ const ProgramState *State);
- ExplodedNode* generateDefaultCaseNode(const GRState* State,
+ ExplodedNode *generateDefaultCaseNode(const ProgramState *State,
bool isSink = false);
- const Expr* getCondition() const { return Condition; }
+ const Expr *getCondition() const { return Condition; }
- const GRState* getState() const { return Pred->State; }
+ const ProgramState *getState() const { return Pred->State; }
};
class GenericNodeBuilderImpl {
@@ -426,10 +431,12 @@ protected:
CoreEngine &engine;
ExplodedNode *pred;
ProgramPoint pp;
- llvm::SmallVector<ExplodedNode*, 2> sinksGenerated;
+ SmallVector<ExplodedNode*, 2> sinksGenerated;
- ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred,
- ProgramPoint programPoint, bool asSink);
+ ExplodedNode *generateNodeImpl(const ProgramState *state,
+ ExplodedNode *pred,
+ ProgramPoint programPoint,
+ bool asSink);
GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
: engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
@@ -439,13 +446,13 @@ public:
WorkList &getWorkList() { return *engine.WList; }
- ExplodedNode* getPredecessor() const { return pred; }
+ ExplodedNode *getPredecessor() const { return pred; }
BlockCounter getBlockCounter() const {
return engine.WList->getBlockCounter();
}
- const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const {
+ const SmallVectorImpl<ExplodedNode*> &sinks() const {
return sinksGenerated;
}
};
@@ -456,8 +463,8 @@ public:
GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
: GenericNodeBuilderImpl(eng, pr, p) {}
- ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
- const void *tag, bool asSink) {
+ ExplodedNode *generateNode(const ProgramState *state, ExplodedNode *pred,
+ const ProgramPointTag *tag, bool asSink) {
return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag),
asSink);
}
@@ -467,27 +474,27 @@ public:
class EndOfFunctionNodeBuilder {
CoreEngine &Eng;
- const CFGBlock& B;
- ExplodedNode* Pred;
- void *Tag;
+ const CFGBlock &B;
+ ExplodedNode *Pred;
+ const ProgramPointTag *Tag;
public:
bool hasGeneratedNode;
public:
- EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e,
- void *checkerTag = 0)
- : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}
+ EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e,
+ const ProgramPointTag *tag = 0)
+ : Eng(*e), B(*b), Pred(N), Tag(tag), hasGeneratedNode(false) {}
~EndOfFunctionNodeBuilder();
- EndOfFunctionNodeBuilder withCheckerTag(void *tag) {
+ EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) {
return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
}
WorkList &getWorkList() { return *Eng.WList; }
- ExplodedNode* getPredecessor() const { return Pred; }
+ ExplodedNode *getPredecessor() const { return Pred; }
BlockCounter getBlockCounter() const {
return Eng.WList->getBlockCounter();
@@ -499,14 +506,15 @@ public:
B.getBlockID());
}
- ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0,
- const void *tag = 0);
+ ExplodedNode *generateNode(const ProgramState *State,
+ ExplodedNode *P = 0,
+ const ProgramPointTag *tag = 0);
- void GenerateCallExitNode(const GRState *state);
+ void GenerateCallExitNode(const ProgramState *state);
- const CFGBlock* getBlock() const { return &B; }
+ const CFGBlock *getBlock() const { return &B; }
- const GRState* getState() const {
+ const ProgramState *getState() const {
return getPredecessor()->getState();
}
};
@@ -535,7 +543,7 @@ public:
const CFGBlock *blk, unsigned idx)
: Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
- const GRState *getState() const { return Pred->getState(); }
+ const ProgramState *getState() const { return Pred->getState(); }
const LocationContext *getLocationContext() const {
return Pred->getLocationContext();
@@ -549,7 +557,7 @@ public:
unsigned getIndex() const { return Index; }
- void generateNode(const GRState *state);
+ void generateNode(const ProgramState *state);
};
class CallExitNodeBuilder {
@@ -562,9 +570,9 @@ public:
const ExplodedNode *getPredecessor() const { return Pred; }
- const GRState *getState() const { return Pred->getState(); }
+ const ProgramState *getState() const { return Pred->getState(); }
- void generateNode(const GRState *state);
+ void generateNode(const ProgramState *state);
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index 193056e6b030..2463e23f5f79 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
#define LLVM_CLANG_GR_ENVIRONMENT_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -43,7 +42,7 @@ private:
Environment(BindingsTy eb)
: ExprBindings(eb) {}
- SVal lookupExpr(const Stmt* E) const;
+ SVal lookupExpr(const Stmt *E) const;
public:
typedef BindingsTy::iterator iterator;
@@ -53,7 +52,7 @@ public:
/// getSVal - Fetches the current binding of the expression in the
/// Environment.
- SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder,
+ SVal getSVal(const Stmt *Ex, SValBuilder& svalBuilder,
bool useOnlyDirectBindings = false) const;
/// Profile - Profile the contents of an Environment object for use
@@ -96,8 +95,7 @@ public:
SVal V);
Environment removeDeadBindings(Environment Env,
- SymbolReaper &SymReaper, const GRState *ST,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ SymbolReaper &SymReaper, const ProgramState *ST);
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index e5d6876fa6b2..fdfed3da5403 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -31,7 +31,7 @@
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
namespace clang {
@@ -67,7 +67,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
return P & 0x1;
}
- void* getPtr() const {
+ void *getPtr() const {
assert (!getFlag());
return reinterpret_cast<void*>(P & ~Mask);
}
@@ -87,7 +87,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
bool empty() const { return (P & ~Mask) == 0; }
- void addNode(ExplodedNode* N, ExplodedGraph &G);
+ void addNode(ExplodedNode *N, ExplodedGraph &G);
void replaceNode(ExplodedNode *node);
@@ -106,7 +106,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
const ProgramPoint Location;
/// State - The state associated with this node.
- const GRState* State;
+ const ProgramState *State;
/// Preds - The predecessors of this node.
NodeGroup Preds;
@@ -116,13 +116,13 @@ class ExplodedNode : public llvm::FoldingSetNode {
public:
- explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
+ explicit ExplodedNode(const ProgramPoint &loc, const ProgramState *state)
: Location(loc), State(state) {
- const_cast<GRState*>(State)->incrementReferenceCount();
+ const_cast<ProgramState*>(State)->incrementReferenceCount();
}
~ExplodedNode() {
- const_cast<GRState*>(State)->decrementReferenceCount();
+ const_cast<ProgramState*>(State)->decrementReferenceCount();
}
/// getLocation - Returns the edge associated with the given node.
@@ -138,17 +138,18 @@ public:
ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
- LiveVariables &getLiveVariables() const {
- return *getLocationContext()->getLiveVariables();
+ template <typename T>
+ T &getAnalysis() const {
+ return *getLocationContext()->getAnalysis<T>();
}
- const GRState* getState() const { return State; }
+ const ProgramState *getState() const { return State; }
template <typename T>
const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
static void Profile(llvm::FoldingSetNodeID &ID,
- const ProgramPoint& Loc, const GRState* state) {
+ const ProgramPoint &Loc, const ProgramState *state) {
ID.Add(Loc);
ID.AddPointer(state);
}
@@ -159,7 +160,7 @@ public:
/// addPredeccessor - Adds a predecessor to the current node, and
/// in tandem add this node as a successor of the other node.
- void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
+ void addPredecessor(ExplodedNode *V, ExplodedGraph &G);
unsigned succ_size() const { return Succs.size(); }
unsigned pred_size() const { return Preds.size(); }
@@ -169,11 +170,11 @@ public:
bool isSink() const { return Succs.getFlag(); }
void markAsSink() { Succs.setFlag(); }
- ExplodedNode* getFirstPred() {
+ ExplodedNode *getFirstPred() {
return pred_empty() ? NULL : *(pred_begin());
}
- const ExplodedNode* getFirstPred() const {
+ const ExplodedNode *getFirstPred() const {
return const_cast<ExplodedNode*>(this)->getFirstPred();
}
@@ -210,7 +211,7 @@ public:
class Auditor {
public:
virtual ~Auditor();
- virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
+ virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0;
};
static void SetAuditor(Auditor* A);
@@ -226,7 +227,7 @@ class InterExplodedGraphMap {
friend class ExplodedGraph;
public:
- ExplodedNode* getMappedNode(const ExplodedNode* N) const;
+ ExplodedNode *getMappedNode(const ExplodedNode *N) const;
InterExplodedGraphMap() {}
virtual ~InterExplodedGraphMap() {}
@@ -237,8 +238,8 @@ protected:
friend class CoreEngine;
// Type definitions.
- typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
- typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy;
+ typedef SmallVector<ExplodedNode*,2> RootsTy;
+ typedef SmallVector<ExplodedNode*,10> EndNodesTy;
/// Roots - The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
@@ -275,7 +276,7 @@ public:
/// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
- ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
+ ExplodedNode *getNode(const ProgramPoint &L, const ProgramState *State,
bool* IsNew = 0);
ExplodedGraph* MakeEmptyGraph() const {
@@ -283,13 +284,13 @@ public:
}
/// addRoot - Add an untyped node to the set of roots.
- ExplodedNode* addRoot(ExplodedNode* V) {
+ ExplodedNode *addRoot(ExplodedNode *V) {
Roots.push_back(V);
return V;
}
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
- ExplodedNode* addEndOfPath(ExplodedNode* V) {
+ ExplodedNode *addEndOfPath(ExplodedNode *V) {
EndNodes.push_back(V);
return V;
}
@@ -368,18 +369,18 @@ class ExplodedNodeSet {
ImplTy Impl;
public:
- ExplodedNodeSet(ExplodedNode* N) {
+ ExplodedNodeSet(ExplodedNode *N) {
assert (N && !static_cast<ExplodedNode*>(N)->isSink());
Impl.insert(N);
}
ExplodedNodeSet() {}
- inline void Add(ExplodedNode* N) {
+ inline void Add(ExplodedNode *N) {
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
}
- ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
+ ExplodedNodeSet &operator=(const ExplodedNodeSet &X) {
Impl = X.Impl;
return *this;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index d24036c0ec28..9bc470fdde60 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -19,9 +19,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
@@ -35,6 +33,8 @@ class ObjCForCollectionStmt;
namespace ento {
class AnalysisManager;
+class CallOrObjCMessage;
+class ObjCMessage;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -49,7 +49,7 @@ class ExprEngine : public SubEngine {
StmtNodeBuilder* Builder;
/// StateMgr - Object that manages the data for all created states.
- GRStateManager StateMgr;
+ ProgramStateManager StateMgr;
/// SymMgr - Object that manages the symbol information.
SymbolManager& SymMgr;
@@ -58,31 +58,32 @@ class ExprEngine : public SubEngine {
SValBuilder &svalBuilder;
/// EntryNode - The immediate predecessor node.
- ExplodedNode* EntryNode;
+ ExplodedNode *EntryNode;
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
- const GRState* CleanedState;
+ const ProgramState *CleanedState;
/// currentStmt - The current block-level statement.
- const Stmt* currentStmt;
+ const Stmt *currentStmt;
- // Obj-C Class Identifiers.
+ /// Obj-C Class Identifiers.
IdentifierInfo* NSExceptionII;
- // Obj-C Selectors.
+ /// Obj-C Selectors.
Selector* NSExceptionInstanceRaiseSelectors;
Selector RaiseSel;
+
+ /// Whether or not GC is enabled in this analysis.
+ bool ObjCGCEnabled;
/// The BugReporter associated with this engine. It is important that
/// this object be placed at the very end of member variables so that its
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
-
- llvm::OwningPtr<TransferFuncs> TF;
public:
- ExprEngine(AnalysisManager &mgr, TransferFuncs *tf);
+ ExprEngine(AnalysisManager &mgr, bool gcEnabled);
~ExprEngine();
@@ -94,13 +95,13 @@ public:
/// of the function are added into the Dst set, which represent the exit
/// state of the function call.
void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
- const GRState *InitState,
+ const ProgramState *InitState,
ExplodedNodeSet &Dst) {
Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
- ASTContext& getContext() const { return AMgr.getASTContext(); }
+ ASTContext &getContext() const { return AMgr.getASTContext(); }
virtual AnalysisManager &getAnalysisManager() { return AMgr; }
@@ -110,14 +111,11 @@ public:
SValBuilder &getSValBuilder() { return svalBuilder; }
- TransferFuncs& getTF() { return *TF; }
-
BugReporter& getBugReporter() { return BR; }
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
- // FIXME: Remove once TransferFuncs is no longer referenced.
- void setTransferFunction(TransferFuncs* tf);
+ bool isObjCGCEnabled() { return ObjCGCEnabled; }
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
@@ -127,7 +125,7 @@ public:
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
- const GRState* getInitialState(const LocationContext *InitLoc);
+ const ProgramState *getInitialState(const LocationContext *InitLoc);
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
@@ -155,7 +153,7 @@ public:
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
- void processBranch(const Stmt* Condition, const Stmt* Term,
+ void processBranch(const Stmt *Condition, const Stmt *Term,
BranchNodeBuilder& builder);
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
@@ -181,21 +179,25 @@ public:
/// evalAssume - Callback function invoked by the ConstraintManager when
/// making assumptions about state values.
- const GRState *processAssume(const GRState *state, SVal cond,bool assumption);
+ const ProgramState *processAssume(const ProgramState *state, SVal cond,bool assumption);
- /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a
+ /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- bool wantsRegionChangeUpdate(const GRState* state);
+ bool wantsRegionChangeUpdate(const ProgramState *state);
- /// processRegionChanges - Called by GRStateManager whenever a change is made
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- const GRState *
- processRegionChanges(const GRState *state,
+ const ProgramState *
+ processRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions);
- virtual GRStateManager& getStateManager() { return StateMgr; }
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep);
+
+ virtual ProgramStateManager& getStateManager() { return StateMgr; }
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
@@ -222,124 +224,109 @@ public:
const CoreEngine &getCoreEngine() const { return Engine; }
-protected:
- const GRState* GetState(ExplodedNode* N) {
- return N == EntryNode ? CleanedState : N->getState();
- }
-
public:
- ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
+ ExplodedNode *MakeNode(ExplodedNodeSet &Dst, const Stmt *S,
+ ExplodedNode *Pred, const ProgramState *St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
- const void *tag = 0);
+ const ProgramPointTag *tag = 0);
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
- void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitArraySubscriptExpr - Transfer function for array accesses.
- void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitAsmStmt - Transfer function logic for inline asm.
- void VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitAsmStmtHelperOutputs(const AsmStmt* A,
+ void VisitAsmStmtHelperOutputs(const AsmStmt *A,
AsmStmt::const_outputs_iterator I,
AsmStmt::const_outputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitAsmStmtHelperInputs(const AsmStmt* A,
+ void VisitAsmStmtHelperInputs(const AsmStmt *A,
AsmStmt::const_inputs_iterator I,
AsmStmt::const_inputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitBinaryOperator - Transfer function logic for binary operators.
- void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitCall - Transfer function for function calls.
- void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
- void VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// Transfer function logic for DeclRefExprs and BlockDeclRefExprs.
- void VisitCommonDeclRefExpr(const Expr* DR, const NamedDecl *D,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
- void VisitDeclStmt(const DeclStmt* DS, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
- void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
- void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitMemberExpr - Transfer function for member expressions.
- void VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// Transfer function logic for ObjCAtSynchronizedStmts.
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
/// Transfer function logic for computing the lvalue of an Objective-C ivar.
- void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitObjCForCollectionStmt - Transfer function logic for
/// ObjCForCollectionStmt.
- void VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst, SVal ElementV);
-
- /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
- void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
- void VisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Src,
- ExplodedNodeSet& Dst);
+ void VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
- void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitOffsetOfExpr - Transfer function for offsetof.
- void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof.
- void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr* Ex,
- ExplodedNode* Pred, ExplodedNodeSet& Dst);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
- void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
@@ -366,7 +353,8 @@ public:
ExplodedNodeSet &Dst);
/// Create a C++ temporary object for an rvalue.
- void CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
+ void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
+ ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// Synthesize CXXThisRegion.
@@ -389,8 +377,11 @@ public:
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
- void evalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src,
+ void evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
+
+ std::pair<const ProgramPointTag *, const ProgramPointTag*>
+ getEagerlyAssumeTags();
SVal evalMinus(SVal X) {
return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
@@ -402,36 +393,36 @@ public:
public:
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc L, NonLoc R, QualType T) {
return svalBuilder.evalBinOpNN(state, op, L, R, T);
}
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
}
- SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal evalBinOp(const ProgramState *ST, BinaryOperator::Opcode Op,
SVal LHS, SVal RHS, QualType T) {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}
protected:
- void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg,
- ExplodedNode* Pred, const GRState *state) {
- assert (Builder && "StmtNodeBuilder must be defined.");
- getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
- }
+ void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
+ ExplodedNode *Pred, const ProgramState *state);
+
+ const ProgramState *invalidateArguments(const ProgramState *State,
+ const CallOrObjCMessage &Call,
+ const LocationContext *LC);
- const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
+ const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator,
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,
- const GRState* St, SVal location, SVal Val,
- bool atDeclInit = false);
+ void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
+ SVal location, SVal Val, bool atDeclInit = false);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
@@ -440,25 +431,25 @@ public:
// be the same as Pred->state, and when 'location' may not be the
// same as state->getLValue(Ex).
/// Simulate a read of the result of Ex.
- void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
- const GRState* St, SVal location, const void *tag = 0,
+ void evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
+ const ProgramState *St, SVal location, const ProgramPointTag *tag = 0,
QualType LoadTy = QualType());
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
- void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE,
- ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
- const void *tag = 0);
+ void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
+ ExplodedNode *Pred, const ProgramState *St, SVal TargetLV, SVal Val,
+ const ProgramPointTag *tag = 0);
private:
- void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
- const GRState* St, SVal location, const void *tag,
+ void evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
+ const ProgramState *St, SVal location, const ProgramPointTag *tag,
QualType LoadTy);
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
- void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred,
- const GRState* St, SVal location,
- const void *tag, bool isLoad);
+ void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode *Pred,
+ const ProgramState *St, SVal location,
+ const ProgramPointTag *tag, bool isLoad);
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
index 18e39d999bb4..89b47dc6ec26 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
@@ -25,9 +25,9 @@ class StmtNodeBuilderRef {
ExplodedNodeSet &Dst;
StmtNodeBuilder &B;
ExprEngine& Eng;
- ExplodedNode* Pred;
- const GRState* state;
- const Stmt* stmt;
+ ExplodedNode *Pred;
+ const ProgramState *state;
+ const Stmt *stmt;
const unsigned OldSize;
const bool AutoCreateNode;
SaveAndRestore<bool> OldSink;
@@ -42,9 +42,9 @@ private:
StmtNodeBuilderRef(ExplodedNodeSet &dst,
StmtNodeBuilder &builder,
ExprEngine& eng,
- ExplodedNode* pred,
- const GRState *st,
- const Stmt* s, bool auto_create_node)
+ ExplodedNode *pred,
+ const ProgramState *st,
+ const Stmt *s, bool auto_create_node)
: Dst(dst), B(builder), Eng(eng), Pred(pred),
state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
OldSink(B.BuildSinks), OldHasGen(B.hasGeneratedNode) {}
@@ -62,13 +62,13 @@ public:
}
}
- const GRState *getState() { return state; }
+ const ProgramState *getState() { return state; }
- GRStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() {
return Eng.getStateManager();
}
- ExplodedNode* MakeNode(const GRState* state) {
+ ExplodedNode *MakeNode(const ProgramState *state) {
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index db7a930b556e..c9941fe90c24 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -19,15 +19,14 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
namespace llvm {
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -83,12 +82,13 @@ public:
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
+ BlockDataRegionKind,
// Typed regions.
BEG_TYPED_REGIONS,
FunctionTextRegionKind = BEG_TYPED_REGIONS,
BlockTextRegionKind,
- BlockDataRegionKind,
- CompoundLiteralRegionKind,
+ BEG_TYPED_VALUE_REGIONS,
+ CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
StringRegionKind,
ElementRegionKind,
@@ -100,6 +100,7 @@ public:
END_DECL_REGIONS = ObjCIvarRegionKind,
CXXTempObjectRegionKind,
CXXBaseObjectRegionKind,
+ END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind,
END_TYPED_REGIONS = CXXBaseObjectRegionKind
};
@@ -136,7 +137,7 @@ public:
/// Compute the offset within the top level memory object.
RegionOffset getAsOffset() const;
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void dump() const;
@@ -197,7 +198,7 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
public:
void Profile(llvm::FoldingSetNodeID &ID) const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
const CodeTextRegion *getCodeRegion() const { return CR; }
@@ -214,7 +215,7 @@ class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
public:
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion *R) {
return R->getKind() == NonStaticGlobalSpaceRegionKind;
@@ -323,14 +324,14 @@ class AllocaRegion : public SubRegion {
protected:
unsigned Cnt; // Block counter. Used to distinguish different pieces of
// memory allocated by alloca at the same call site.
- const Expr* Ex;
+ const Expr *Ex;
- AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
+ AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion)
: SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
public:
- const Expr* getExpr() const { return Ex; }
+ const Expr *getExpr() const { return Ex; }
bool isBoundable() const { return true; }
@@ -338,10 +339,10 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
unsigned Cnt, const MemRegion *superRegion);
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == AllocaRegionKind;
@@ -354,6 +355,26 @@ protected:
TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
public:
+ virtual QualType getLocationType() const = 0;
+
+ QualType getDesugaredLocationType(ASTContext &Context) const {
+ return getLocationType().getDesugaredType(Context);
+ }
+
+ bool isBoundable() const { return true; }
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ }
+};
+
+/// TypedValueRegion - An abstract class representing regions having a typed value.
+class TypedValueRegion : public TypedRegion {
+protected:
+ TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {}
+
+public:
virtual QualType getValueType() const = 0;
virtual QualType getLocationType() const {
@@ -370,15 +391,9 @@ public:
return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
}
- QualType getDesugaredLocationType(ASTContext &Context) const {
- return getLocationType().getDesugaredType(Context);
- }
-
- bool isBoundable() const { return true; }
-
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
}
};
@@ -387,11 +402,6 @@ class CodeTextRegion : public TypedRegion {
protected:
CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
public:
- QualType getValueType() const {
- assert(0 && "Do not get the object type of a CodeTextRegion.");
- return QualType();
- }
-
bool isBoundable() const { return false; }
static bool classof(const MemRegion* R) {
@@ -404,7 +414,7 @@ public:
class FunctionTextRegion : public CodeTextRegion {
const FunctionDecl *FD;
public:
- FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
+ FunctionTextRegion(const FunctionDecl *fd, const MemRegion* sreg)
: CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
QualType getLocationType() const {
@@ -415,7 +425,7 @@ public:
return FD;
}
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -456,7 +466,7 @@ public:
AnalysisContext *getAnalysisContext() const { return AC; }
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -509,7 +519,7 @@ public:
bool operator!=(const referenced_vars_iterator &I) const {
return I.R != R;
}
- referenced_vars_iterator& operator++() {
+ referenced_vars_iterator &operator++() {
++R;
return *this;
}
@@ -518,7 +528,7 @@ public:
referenced_vars_iterator referenced_vars_begin() const;
referenced_vars_iterator referenced_vars_end() const;
- virtual void dumpToStream(llvm::raw_ostream& os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -559,7 +569,7 @@ public:
SymbolRef sym,
const MemRegion* superRegion);
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == SymbolicRegionKind;
@@ -567,13 +577,13 @@ public:
};
/// StringRegion - Region associated with a StringLiteral.
-class StringRegion : public TypedRegion {
+class StringRegion : public TypedValueRegion {
friend class MemRegionManager;
const StringLiteral* Str;
protected:
StringRegion(const StringLiteral* str, const MemRegion* sreg)
- : TypedRegion(sreg, StringRegionKind), Str(str) {}
+ : TypedValueRegion(sreg, StringRegionKind), Str(str) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
@@ -595,7 +605,7 @@ public:
ProfileRegion(ID, Str, superRegion);
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == StringRegionKind;
@@ -605,16 +615,16 @@ public:
/// CompoundLiteralRegion - A memory region representing a compound literal.
/// Compound literals are essentially temporaries that are stack allocated
/// or in the global constant pool.
-class CompoundLiteralRegion : public TypedRegion {
+class CompoundLiteralRegion : public TypedValueRegion {
private:
friend class MemRegionManager;
- const CompoundLiteralExpr* CL;
+ const CompoundLiteralExpr *CL;
- CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
- : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+ CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg)
+ : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
- const CompoundLiteralExpr* CL,
+ const CompoundLiteralExpr *CL,
const MemRegion* superRegion);
public:
QualType getValueType() const {
@@ -625,27 +635,27 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
- const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
+ const CompoundLiteralExpr *getLiteralExpr() const { return CL; }
static bool classof(const MemRegion* R) {
return R->getKind() == CompoundLiteralRegionKind;
}
};
-class DeclRegion : public TypedRegion {
+class DeclRegion : public TypedValueRegion {
protected:
- const Decl* D;
+ const Decl *D;
- DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
- : TypedRegion(sReg, k), D(d) {}
+ DeclRegion(const Decl *d, const MemRegion* sReg, Kind k)
+ : TypedValueRegion(sReg, k), D(d) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k);
public:
- const Decl* getDecl() const { return D; }
+ const Decl *getDecl() const { return D; }
void Profile(llvm::FoldingSetNodeID& ID) const;
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
@@ -660,10 +670,10 @@ class VarRegion : public DeclRegion {
friend class MemRegionManager;
// Constructors and private methods.
- VarRegion(const VarDecl* vd, const MemRegion* sReg)
+ VarRegion(const VarDecl *vd, const MemRegion* sReg)
: DeclRegion(vd, sReg, VarRegionKind) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
const MemRegion *superRegion) {
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
}
@@ -680,7 +690,7 @@ public:
return getDecl()->getType();
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == VarRegionKind;
@@ -690,11 +700,11 @@ public:
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
/// in a call to a C++ method. This region doesn't represent the object
/// referred to by 'this', but rather 'this' itself.
-class CXXThisRegion : public TypedRegion {
+class CXXThisRegion : public TypedValueRegion {
friend class MemRegionManager;
CXXThisRegion(const PointerType *thisPointerTy,
const MemRegion *sReg)
- : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+ : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const PointerType *PT,
@@ -707,7 +717,7 @@ public:
return QualType(ThisPointerTy, 0);
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == CXXThisRegionKind;
@@ -720,14 +730,14 @@ private:
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
- FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
+ FieldRegion(const FieldDecl *fd, const MemRegion* sReg)
: DeclRegion(fd, sReg, FieldRegionKind) {}
public:
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
- const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
+ const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
QualType getValueType() const {
// FIXME: We can cache this if needed.
@@ -736,7 +746,7 @@ public:
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
const MemRegion* superRegion) {
DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
}
@@ -750,19 +760,19 @@ class ObjCIvarRegion : public DeclRegion {
friend class MemRegionManager;
- ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg)
: DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
const MemRegion* superRegion) {
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
}
public:
- const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
+ const ObjCIvarDecl *getDecl() const { return cast<ObjCIvarDecl>(D); }
QualType getValueType() const { return getDecl()->getType(); }
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
return R->getKind() == ObjCIvarRegionKind;
@@ -789,18 +799,18 @@ public:
CharUnits getOffset() const { return Offset; }
const MemRegion *getRegion() const { return Region; }
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void dump() const;
};
-class ElementRegion : public TypedRegion {
+class ElementRegion : public TypedValueRegion {
friend class MemRegionManager;
QualType ElementType;
NonLoc Index;
ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
- : TypedRegion(sReg, ElementRegionKind),
+ : TypedValueRegion(sReg, ElementRegionKind),
ElementType(elementType), Index(Idx) {
assert((!isa<nonloc::ConcreteInt>(&Idx) ||
cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
@@ -824,7 +834,7 @@ public:
/// Compute the offset within the array. The array might also be a subobject.
RegionRawOffset getAsArrayOffset() const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
@@ -834,23 +844,25 @@ public:
};
// C++ temporary object associated with an expression.
-class CXXTempObjectRegion : public TypedRegion {
+class CXXTempObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
Expr const *Ex;
CXXTempObjectRegion(Expr const *E, MemRegion const *sReg)
- : TypedRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
+ : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
Expr const *E, const MemRegion *sReg);
public:
+ const Expr *getExpr() const { return Ex; }
+
QualType getValueType() const {
return Ex->getType();
}
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -861,13 +873,13 @@ public:
// CXXBaseObjectRegion represents a base object within a C++ object. It is
// identified by the base class declaration and the region of its parent object.
-class CXXBaseObjectRegion : public TypedRegion {
+class CXXBaseObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
const CXXRecordDecl *decl;
CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
- : TypedRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
+ : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const CXXRecordDecl *decl, const MemRegion *sReg);
@@ -877,7 +889,7 @@ public:
QualType getValueType() const;
- void dumpToStream(llvm::raw_ostream& os) const;
+ void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -951,13 +963,13 @@ public:
const MemSpaceRegion *getCodeRegion();
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
- const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt,
+ const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
const LocationContext *LC);
/// getCompoundLiteralRegion - Retrieve the region associated with a
/// given CompoundLiteral.
const CompoundLiteralRegion*
- getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+ getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC);
/// getCXXThisRegion - Retrieve the [artificial] region associated with the
@@ -994,7 +1006,7 @@ public:
/// a specified FieldDecl. 'superRegion' corresponds to the containing
/// memory region (which typically represents the memory representing
/// a structure or class).
- const FieldRegion *getFieldRegion(const FieldDecl* fd,
+ const FieldRegion *getFieldRegion(const FieldDecl *fd,
const MemRegion* superRegion);
const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
@@ -1006,7 +1018,7 @@ public:
/// a specified Objective-c instance variable. 'superRegion' corresponds
/// to the containing region (which typically represents the Objective-C
/// object).
- const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
+ const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
const MemRegion* superRegion);
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
@@ -1069,7 +1081,7 @@ private:
// Out-of-line member definitions.
//===----------------------------------------------------------------------===//
-inline ASTContext& MemRegion::getContext() const {
+inline ASTContext &MemRegion::getContext() const {
return getMemRegionManager()->getContext();
}
@@ -1082,7 +1094,7 @@ inline ASTContext& MemRegion::getContext() const {
//===----------------------------------------------------------------------===//
namespace llvm {
-static inline raw_ostream& operator<<(raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
const clang::ento::MemRegion* R) {
R->dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 734024c2cba4..add3479804bd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -16,8 +16,10 @@
#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/PointerUnion.h"
namespace clang {
namespace ento {
@@ -86,6 +88,21 @@ public:
return 0;
}
+ SVal getInstanceReceiverSVal(const ProgramState *State,
+ const LocationContext *LC) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (!isInstanceMessage())
+ return UndefinedVal();
+ if (const Expr *Ex = getInstanceReceiver())
+ return State->getSValAsScalarOrLoc(Ex);
+
+ // 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 {
assert(isValid() && "This ObjCMessage is uninitialized!");
if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
@@ -96,7 +113,7 @@ public:
}
const ObjCMethodDecl *getMethodDecl() const;
-
+
const ObjCInterfaceDecl *getReceiverInterface() const;
SourceLocation getSuperLoc() const {
@@ -106,45 +123,63 @@ public:
return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
}
- SourceRange getSourceRange() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
+ const Expr *getMsgOrPropExpr() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ return MsgOrPropE;
+ }
+
+ SourceRange getSourceRange() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
return MsgOrPropE->getSourceRange();
}
- unsigned getNumArgs() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getNumArgs();
- return isPropertySetter() ? 1 : 0;
- }
-
- SVal getArgSVal(unsigned i, const GRState *state) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return state->getSVal(msgE->getArg(i));
- assert(isPropertySetter());
- return SetterArgV;
- }
-
- QualType getArgType(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getArg(i)->getType();
- assert(isPropertySetter());
- return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
- }
-
- const Expr *getArgExpr(unsigned i) const;
-
- SourceRange getArgSourceRange(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const Expr *argE = getArgExpr(i))
- return argE->getSourceRange();
- return OriginE->getSourceRange();
- }
+ unsigned getNumArgs() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getNumArgs();
+ return isPropertySetter() ? 1 : 0;
+ }
+
+ SVal getArgSVal(unsigned i, const ProgramState *state) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return state->getSVal(msgE->getArg(i));
+ assert(isPropertySetter());
+ return SetterArgV;
+ }
+
+ QualType getArgType(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getArg(i)->getType();
+ assert(isPropertySetter());
+ return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+ }
+
+ const Expr *getArgExpr(unsigned i) const;
+
+ SourceRange getArgSourceRange(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const Expr *argE = getArgExpr(i))
+ return argE->getSourceRange();
+ return OriginE->getSourceRange();
+ }
+
+ SourceRange getReceiverSourceRange() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getReceiverRange();
+
+ const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+ if (propE->isObjectReceiver())
+ return propE->getBase()->getSourceRange();
+
+ // FIXME: This isn't a range.
+ return propE->getReceiverLocation();
+ }
};
class ObjCPropertyGetter : public ObjCMessage {
@@ -165,58 +200,89 @@ public:
}
};
-/// \brief Common wrapper for a call expression or an ObjC message, mainly to
-/// provide a common interface for handling their arguments.
+/// \brief Common wrapper for a call expression, ObjC message, or C++
+/// constructor, mainly to provide a common interface for their arguments.
class CallOrObjCMessage {
- const CallExpr *CallE;
+ llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
ObjCMessage Msg;
- const GRState *State;
+ const ProgramState *State;
public:
- CallOrObjCMessage(const CallExpr *callE, const GRState *state)
+ CallOrObjCMessage(const CallExpr *callE, const ProgramState *state)
: CallE(callE), State(state) {}
- CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
- : CallE(0), Msg(msg), State(state) {}
+ CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state)
+ : CallE(consE), State(state) {}
+ CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state)
+ : CallE((CallExpr *)0), Msg(msg), State(state) {}
QualType getResultType(ASTContext &ctx) const;
bool isFunctionCall() const {
- return (bool) CallE;
+ return CallE && CallE.is<const CallExpr *>();
}
-
+
+ bool isCXXConstructExpr() const {
+ return CallE && CallE.is<const CXXConstructExpr *>();
+ }
+
+ bool isObjCMessage() const {
+ return !CallE;
+ }
+
bool isCXXCall() const {
- return CallE && isa<CXXMemberCallExpr>(CallE);
+ const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
+ return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
+ }
+
+ const Expr *getOriginExpr() const {
+ if (!CallE)
+ return Msg.getOriginExpr();
+ 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;
unsigned getNumArgs() const {
- if (CallE) return CallE->getNumArgs();
- return Msg.getNumArgs();
+ 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 State->getSVal(CallE->getArg(i));
- return Msg.getArgSVal(i, State);
+ if (!CallE)
+ return Msg.getArgSVal(i, State);
+ return State->getSVal(getArg(i));
}
- SVal getArgSValAsScalarOrLoc(unsigned i) const;
-
const Expr *getArg(unsigned i) const {
assert(i < getNumArgs());
- if (CallE)
- return CallE->getArg(i);
- return Msg.getArgExpr(i);
+ 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 CallE->getArg(i)->getSourceRange();
+ return getArg(i)->getSourceRange();
return Msg.getArgSourceRange(i);
}
+
+ SourceRange getReceiverSourceRange() const {
+ assert(isObjCMessage());
+ return Msg.getReceiverSourceRange();
+ }
};
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 0d61d0e620eb..edae06e68c34 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -1,4 +1,4 @@
-//== GRState.h - Path-sensitive "State" for tracking values -----*- C++ -*--==//
+//== ProgramState.h - Path-sensitive "State" for tracking values -*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,13 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and GRState*.
+// This file defines SymbolRef, ExprBindKey, and ProgramState*.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_VALUESTATE_H
#define LLVM_CLANG_GR_VALUESTATE_H
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
@@ -21,12 +22,10 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/Support/Casting.h"
namespace llvm {
class APSInt;
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -34,30 +33,31 @@ class ASTContext;
namespace ento {
-class GRStateManager;
+class ProgramStateManager;
-typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
+typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
SubEngine&);
-typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
+typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&);
//===----------------------------------------------------------------------===//
-// GRStateTrait - Traits used by the Generic Data Map of a GRState.
+// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
//===----------------------------------------------------------------------===//
-template <typename T> struct GRStatePartialTrait;
+template <typename T> struct ProgramStatePartialTrait;
-template <typename T> struct GRStateTrait {
+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) {
+ 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 GRStateManager;
+class ProgramStateManager;
-/// GRState - This class encapsulates:
+/// \class ProgramState
+/// ProgramState - This class encapsulates:
///
/// 1. A mapping from expressions to values (Environment)
/// 2. A mapping from locations to values (Store)
@@ -65,47 +65,47 @@ class GRStateManager;
///
/// Together these represent the "abstract state" of a program.
///
-/// GRState is intended to be used as a functional object; that is,
+/// ProgramState is intended to be used as a functional object; that is,
/// once it is created and made "persistent" in a FoldingSet, its
/// values will never change.
-class GRState : public llvm::FoldingSetNode {
+class ProgramState : public llvm::FoldingSetNode {
public:
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
- void operator=(const GRState& R) const; // Do not implement.
+ void operator=(const ProgramState& R) const; // Do not implement.
- friend class GRStateManager;
+ friend class ProgramStateManager;
friend class ExplodedGraph;
friend class ExplodedNode;
- GRStateManager *stateMgr;
+ ProgramStateManager *stateMgr;
Environment Env; // Maps a Stmt to its current SVal.
Store store; // Maps a location to its current value.
GenericDataMap GDM; // Custom data stored by a client of this class.
unsigned refCount;
- /// makeWithStore - Return a GRState with the same values as the current
+ /// makeWithStore - Return a ProgramState with the same values as the current
/// state with the exception of using the specified Store.
- const GRState *makeWithStore(const StoreRef &store) const;
+ const ProgramState *makeWithStore(const StoreRef &store) const;
void setStore(const StoreRef &storeRef);
public:
- /// This ctor is used when creating the first GRState object.
- GRState(GRStateManager *mgr, const Environment& env,
+ /// This ctor is used when creating the first ProgramState object.
+ ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm);
/// Copy ctor - We must explicitly define this or else the "Next" ptr
/// in FoldingSetNode will also get copied.
- GRState(const GRState& RHS);
+ ProgramState(const ProgramState &RHS);
- ~GRState();
+ ~ProgramState();
- /// Return the GRStateManager associated with this state.
- GRStateManager &getStateManager() const { return *stateMgr; }
+ /// Return the ProgramStateManager associated with this state.
+ ProgramStateManager &getStateManager() const { return *stateMgr; }
/// Return true if this state is referenced by a persistent ExplodedNode.
bool referencedByExplodedNode() const { return refCount > 0; }
@@ -124,10 +124,10 @@ public:
void setGDM(GenericDataMap gdm) { GDM = gdm; }
- /// Profile - Profile the contents of a GRState object for use in a
- /// FoldingSet. Two GRState objects are considered equal if they
+ /// Profile - Profile the contents of a ProgramState object for use in a
+ /// FoldingSet. Two ProgramState objects are considered equal if they
/// have the same Environment, Store, and GenericDataMap.
- static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+ static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) {
V->Env.Profile(ID);
ID.AddPointer(V->store);
V->GDM.Profile(ID);
@@ -146,44 +146,41 @@ public:
// Constraints on values.
//==---------------------------------------------------------------------==//
//
- // Each GRState records constraints on symbolic values. These constraints
- // are managed using the ConstraintManager associated with a GRStateManager.
+ // Each ProgramState records constraints on symbolic values. These constraints
+ // are managed using the ConstraintManager associated with a ProgramStateManager.
// As constraints gradually accrue on symbolic values, added constraints
// may conflict and indicate that a state is infeasible (as no real values
// could satisfy all the constraints). This is the principal mechanism
- // for modeling path-sensitivity in ExprEngine/GRState.
+ // for modeling path-sensitivity in ExprEngine/ProgramState.
//
// Various "assume" methods form the interface for adding constraints to
// symbolic values. A call to 'assume' indicates an assumption being placed
// on one or symbolic values. 'assume' methods take the following inputs:
//
- // (1) A GRState object representing the current state.
+ // (1) A ProgramState object representing the current state.
//
// (2) The assumed constraint (which is specific to a given "assume" method).
//
// (3) A binary value "Assumption" that indicates whether the constraint is
// assumed to be true or false.
//
- // The output of "assume*" is a new GRState object with the added constraints.
+ // The output of "assume*" is a new ProgramState object with the added constraints.
// If no new state is feasible, NULL is returned.
//
- const GRState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
+ const ProgramState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
/// This method assumes both "true" and "false" for 'cond', and
/// returns both corresponding states. It's shorthand for doing
/// 'assume' twice.
- std::pair<const GRState*, const GRState*>
+ std::pair<const ProgramState*, const ProgramState*>
assume(DefinedOrUnknownSVal cond) const;
- const GRState *assumeInBound(DefinedOrUnknownSVal idx,
+ const ProgramState *assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption) const;
- //==---------------------------------------------------------------------==//
- // Utility methods for getting regions.
- //==---------------------------------------------------------------------==//
-
+ /// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
//==---------------------------------------------------------------------==//
@@ -192,52 +189,42 @@ public:
/// BindCompoundLiteral - Return the state that has the bindings currently
/// in this state plus the bindings for the CompoundLiteral.
- const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
+ const ProgramState *bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
- const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+ const ProgramState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
/// Create a new state by binding the value 'V' and location 'locaton' to the
/// statement 'S' in the state's environment.
- const GRState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
+ const ProgramState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
const;
- const GRState *bindDecl(const VarRegion *VR, SVal V) const;
+ const ProgramState *bindDecl(const VarRegion *VR, SVal V) const;
- const GRState *bindDeclWithNoInit(const VarRegion *VR) const;
+ const ProgramState *bindDeclWithNoInit(const VarRegion *VR) const;
- const GRState *bindLoc(Loc location, SVal V) const;
+ const ProgramState *bindLoc(Loc location, SVal V) const;
- const GRState *bindLoc(SVal location, SVal V) const;
+ const ProgramState *bindLoc(SVal location, SVal V) const;
- const GRState *bindDefault(SVal loc, SVal V) const;
+ const ProgramState *bindDefault(SVal loc, SVal V) const;
- const GRState *unbindLoc(Loc LV) const;
-
- /// invalidateRegion - Returns the state with bindings for the given region
- /// cleared from the store. See invalidateRegions.
- const GRState *invalidateRegion(const MemRegion *R,
- const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols *IS = NULL)
- const {
- return invalidateRegions(&R, &R+1, E, BlockCount, IS, false);
- }
+ const ProgramState *unbindLoc(Loc LV) const;
/// invalidateRegions - Returns the state with bindings for the given regions
/// cleared from the store. The regions are provided as a continuous array
/// from Begin to End. Optionally invalidates global regions as well.
- const GRState *invalidateRegions(const MemRegion * const *Begin,
- const MemRegion * const *End,
+ const ProgramState *invalidateRegions(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols *IS,
- bool invalidateGlobals) const;
+ StoreManager::InvalidatedSymbols *IS = 0,
+ bool invalidateGlobals = false) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
- const GRState *enterStackFrame(const StackFrameContext *frame) const;
+ const ProgramState *enterStackFrame(const StackFrameContext *frame) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
@@ -260,7 +247,7 @@ public:
const llvm::APSInt *getSymVal(SymbolRef sym) const;
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt* S, bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const Stmt *S, bool useOnlyDirectBindings = false) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
@@ -273,11 +260,22 @@ public:
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+ /// \brief Visits the symbols reachable from the given SVal using the provided
+ /// SymbolVisitor.
+ ///
+ /// This is a convenience API. Consider using ScanReachableSymbols class
+ /// directly when making multiple scans on the same state with the same
+ /// visitor to avoid repeated initialization cost.
+ /// \sa ScanReachableSymbols
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
+ /// \brief Visits the symbols reachable from the SVals in the given range
+ /// using the provided SymbolVisitor.
bool scanReachableSymbols(const SVal *I, const SVal *E,
SymbolVisitor &visitor) const;
+ /// \brief Visits the symbols reachable from the regions in the given
+ /// MemRegions range using the provided SymbolVisitor.
bool scanReachableSymbols(const MemRegion * const *I,
const MemRegion * const *E,
SymbolVisitor &visitor) const;
@@ -294,70 +292,62 @@ public:
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
- void* const* FindGDM(void* K) const;
+ void *const* FindGDM(void *K) const;
template<typename T>
- const GRState *add(typename GRStateTrait<T>::key_type K) const;
+ const ProgramState *add(typename ProgramStateTrait<T>::key_type K) const;
template <typename T>
- typename GRStateTrait<T>::data_type
+ typename ProgramStateTrait<T>::data_type
get() const {
- return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
+ return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex()));
}
template<typename T>
- typename GRStateTrait<T>::lookup_type
- get(typename GRStateTrait<T>::key_type key) const {
- void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
- return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
+ typename ProgramStateTrait<T>::lookup_type
+ get(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key);
}
template <typename T>
- typename GRStateTrait<T>::context_type get_context() const;
+ typename ProgramStateTrait<T>::context_type get_context() const;
template<typename T>
- const GRState *remove(typename GRStateTrait<T>::key_type K) const;
+ const ProgramState *remove(typename ProgramStateTrait<T>::key_type K) const;
template<typename T>
- const GRState *remove(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) const;
+ const ProgramState *remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const;
template <typename T>
- const GRState *remove() const;
+ const ProgramState *remove() const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::data_type D) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::data_type D) const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const;
template<typename T>
- const GRState *set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E,
- typename GRStateTrait<T>::context_type C) const;
+ const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const;
template<typename T>
- bool contains(typename GRStateTrait<T>::key_type key) const {
- void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
- return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
+ bool contains(typename ProgramStateTrait<T>::key_type key) const {
+ void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex());
+ return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key);
}
- // State pretty-printing.
- class Printer {
- public:
- virtual ~Printer() {}
- virtual void Print(llvm::raw_ostream& Out, const GRState* state,
- const char* nl, const char* sep) = 0;
- };
-
// Pretty-printing.
- void print(llvm::raw_ostream& Out, CFG &C, const char *nl = "\n",
+ void print(raw_ostream &Out, CFG &C, const char *nl = "\n",
const char *sep = "") const;
void printStdErr(CFG &C) const;
- void printDOT(llvm::raw_ostream& Out, CFG &C) const;
+ void printDOT(raw_ostream &Out, CFG &C) const;
private:
/// Increments the number of times this state is referenced by ExplodeNodes.
@@ -369,20 +359,20 @@ private:
--refCount;
}
- const GRState *invalidateRegionsImpl(const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols &IS,
- bool invalidateGlobals) const;
+ const ProgramState *
+ invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ const Expr *E, unsigned BlockCount,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const;
};
-class GRStateSet {
- typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
+class ProgramStateSet {
+ typedef llvm::SmallPtrSet<const ProgramState*,5> ImplTy;
ImplTy Impl;
public:
- GRStateSet() {}
+ ProgramStateSet() {}
- inline void Add(const GRState* St) {
+ inline void Add(const ProgramState *St) {
Impl.insert(St);
}
@@ -395,11 +385,11 @@ public:
inline iterator end() const { return Impl.end(); }
class AutoPopulate {
- GRStateSet& S;
+ ProgramStateSet &S;
unsigned StartSize;
- const GRState* St;
+ const ProgramState *St;
public:
- AutoPopulate(GRStateSet& s, const GRState* st)
+ AutoPopulate(ProgramStateSet &s, const ProgramState *st)
: S(s), StartSize(S.size()), St(st) {}
~AutoPopulate() {
@@ -410,12 +400,11 @@ public:
};
//===----------------------------------------------------------------------===//
-// GRStateManager - Factory object for GRStates.
+// ProgramStateManager - Factory object for ProgramStates.
//===----------------------------------------------------------------------===//
-class GRStateManager {
- friend class GRState;
- friend class ExprEngine; // FIXME: Remove.
+class ProgramStateManager {
+ friend class ProgramState;
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine *Eng; /* Can be null. */
@@ -424,18 +413,14 @@ private:
llvm::OwningPtr<StoreManager> StoreMgr;
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
- GRState::GenericDataMap::Factory GDMFactory;
+ ProgramState::GenericDataMap::Factory GDMFactory;
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
- /// Printers - A set of printer objects used for pretty-printing a GRState.
- /// GRStateManager owns these objects.
- std::vector<GRState::Printer*> Printers;
-
/// StateSet - FoldingSet containing all the states created for analyzing
/// a particular function. This is used to unique states.
- llvm::FoldingSet<GRState> StateSet;
+ llvm::FoldingSet<ProgramState> StateSet;
/// Object that manages the data for all created SVals.
llvm::OwningPtr<SValBuilder> svalBuilder;
@@ -443,15 +428,15 @@ private:
/// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
- /// A vector of recently allocated GRStates that can potentially be
+ /// A vector of recently allocated ProgramStates that can potentially be
/// reused.
- std::vector<GRState *> recentlyAllocatedStates;
+ std::vector<ProgramState *> recentlyAllocatedStates;
- /// A vector of GRStates that we can reuse.
- std::vector<GRState *> freeStates;
+ /// A vector of ProgramStates that we can reuse.
+ std::vector<ProgramState *> freeStates;
public:
- GRStateManager(ASTContext& Ctx,
+ ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
@@ -465,7 +450,7 @@ public:
ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
}
- GRStateManager(ASTContext& Ctx,
+ ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManager* ConstraintManagerPtr,
llvm::BumpPtrAllocator& alloc)
@@ -478,9 +463,9 @@ public:
ConstraintMgr.reset(ConstraintManagerPtr);
}
- ~GRStateManager();
+ ~ProgramStateManager();
- const GRState *getInitialState(const LocationContext *InitLoc);
+ const ProgramState *getInitialState(const LocationContext *InitLoc);
ASTContext &getContext() { return svalBuilder->getContext(); }
const ASTContext &getContext() const { return svalBuilder->getContext(); }
@@ -516,13 +501,13 @@ public:
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
SubEngine* getOwningEngine() { return Eng; }
- const GRState* removeDeadBindings(const GRState* St,
+ const ProgramState *removeDeadBindings(const ProgramState *St,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
/// Marshal a new state for the callee in another translation unit.
/// 'state' is owned by the caller's engine.
- const GRState *MarshalState(const GRState *state, const StackFrameContext *L);
+ const ProgramState *MarshalState(const ProgramState *state, const StackFrameContext *L);
public:
@@ -531,18 +516,28 @@ public:
}
// Methods that manipulate the GDM.
- const GRState* addGDM(const GRState* St, void* Key, void* Data);
- const GRState *removeGDM(const GRState *state, void *Key);
+ const ProgramState *addGDM(const ProgramState *St, void *Key, void *Data);
+ const ProgramState *removeGDM(const ProgramState *state, void *Key);
// Methods that query & manipulate the Store.
- void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
+ void iterBindings(const ProgramState *state, StoreManager::BindingsHandler& F) {
StoreMgr->iterBindings(state->getStore(), F);
}
- const GRState* getPersistentState(GRState& Impl);
-
- /// Periodically called by ExprEngine to recycle GRStates that were
+ const ProgramState *getPersistentState(ProgramState &Impl);
+ const ProgramState *getPersistentStateWithGDM(const ProgramState *FromState,
+ const ProgramState *GDMState);
+
+ bool haveEqualEnvironments(const ProgramState * S1, const ProgramState * S2) {
+ return S1->Env == S2->Env;
+ }
+
+ bool haveEqualStores(const ProgramState * S1, const ProgramState * S2) {
+ return S1->store == S2->store;
+ }
+
+ /// Periodically called by ExprEngine to recycle ProgramStates that were
/// created but never used for creating an ExplodedNode.
void recycleUnusedStates();
@@ -550,9 +545,9 @@ public:
// Generic Data Map methods.
//==---------------------------------------------------------------------==//
//
- // GRStateManager and GRState support a "generic data map" that allows
- // different clients of GRState objects to embed arbitrary data within a
- // GRState object. The generic data map is essentially an immutable map
+ // ProgramStateManager and ProgramState support a "generic data map" that allows
+ // different clients of ProgramState objects to embed arbitrary data within a
+ // ProgramState object. The generic data map is essentially an immutable map
// from a "tag" (that acts as the "key" for a client) and opaque values.
// Tags/keys and values are simply void* values. The typical way that clients
// generate unique tags are by taking the address of a static variable.
@@ -560,82 +555,82 @@ public:
// the data pointer are immutable (and thus are essentially purely functional
// data).
//
- // The templated methods below use the GRStateTrait<T> class
+ // The templated methods below use the ProgramStateTrait<T> class
// to resolve keys into the GDM and to return data values to clients.
//
// Trait based GDM dispatch.
template <typename T>
- const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(D));
+ const ProgramState *set(const ProgramState *st, typename ProgramStateTrait<T>::data_type D) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(D));
}
template<typename T>
- const GRState* set(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type V,
- typename GRStateTrait<T>::context_type C) {
+ const ProgramState *set(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type V,
+ typename ProgramStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C)));
}
template <typename T>
- const GRState* add(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
+ const ProgramState *add(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C)));
}
template <typename T>
- const GRState* remove(const GRState* st,
- typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) {
+ const ProgramState *remove(const ProgramState *st,
+ typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) {
- return addGDM(st, GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
+ return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C)));
}
template <typename T>
- const GRState *remove(const GRState *st) {
- return removeGDM(st, GRStateTrait<T>::GDMIndex());
+ const ProgramState *remove(const ProgramState *st) {
+ return removeGDM(st, ProgramStateTrait<T>::GDMIndex());
}
- void* FindGDMContext(void* index,
- void* (*CreateContext)(llvm::BumpPtrAllocator&),
+ void *FindGDMContext(void *index,
+ void *(*CreateContext)(llvm::BumpPtrAllocator&),
void (*DeleteContext)(void*));
template <typename T>
- typename GRStateTrait<T>::context_type get_context() {
- void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
- GRStateTrait<T>::CreateContext,
- GRStateTrait<T>::DeleteContext);
+ typename ProgramStateTrait<T>::context_type get_context() {
+ void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(),
+ ProgramStateTrait<T>::CreateContext,
+ ProgramStateTrait<T>::DeleteContext);
- return GRStateTrait<T>::MakeContext(p);
+ return ProgramStateTrait<T>::MakeContext(p);
}
- const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
+ const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) {
return ConstraintMgr->getSymVal(St, sym);
}
- void EndPath(const GRState* St) {
+ void EndPath(const ProgramState *St) {
ConstraintMgr->EndPath(St);
}
};
//===----------------------------------------------------------------------===//
-// Out-of-line method definitions for GRState.
+// Out-of-line method definitions for ProgramState.
//===----------------------------------------------------------------------===//
-inline const VarRegion* GRState::getRegion(const VarDecl *D,
+inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
const LocationContext *LC) const {
return getStateManager().getRegionManager().getVarRegion(D, LC);
}
-inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
+inline const ProgramState *ProgramState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
@@ -644,8 +639,8 @@ inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
Assumption);
}
-inline std::pair<const GRState*, const GRState*>
-GRState::assume(DefinedOrUnknownSVal Cond) const {
+inline std::pair<const ProgramState*, const ProgramState*>
+ProgramState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
@@ -653,48 +648,48 @@ GRState::assume(DefinedOrUnknownSVal Cond) const {
cast<DefinedSVal>(Cond));
}
-inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
+inline const ProgramState *ProgramState::bindLoc(SVal LV, SVal V) const {
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
}
-inline Loc GRState::getLValue(const VarDecl* VD,
+inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueVar(VD, LC);
}
-inline Loc GRState::getLValue(const StringLiteral *literal) const {
+inline Loc ProgramState::getLValue(const StringLiteral *literal) const {
return getStateManager().StoreMgr->getLValueString(literal);
}
-inline Loc GRState::getLValue(const CompoundLiteralExpr *literal,
+inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
}
-inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
+inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueIvar(D, Base);
}
-inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
+inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {
return getStateManager().StoreMgr->getLValueField(D, Base);
}
-inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+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);
return UnknownVal();
}
-inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
+inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const {
return getStateManager().getSymVal(this, sym);
}
-inline SVal GRState::getSVal(const Stmt* Ex, bool useOnlyDirectBindings) const{
+inline SVal ProgramState::getSVal(const Stmt *Ex, bool useOnlyDirectBindings) const{
return Env.getSVal(Ex, *getStateManager().svalBuilder,
- useOnlyDirectBindings);
+ useOnlyDirectBindings);
}
-inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
+inline SVal ProgramState::getSValAsScalarOrLoc(const Stmt *S) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType())
@@ -704,88 +699,114 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
return UnknownVal();
}
-inline SVal GRState::getRawSVal(Loc LV, QualType T) const {
+inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const {
return getStateManager().StoreMgr->Retrieve(getStore(), LV, T);
}
-inline SVal GRState::getSVal(const MemRegion* R) const {
+inline SVal ProgramState::getSVal(const MemRegion* R) const {
return getStateManager().StoreMgr->Retrieve(getStore(), loc::MemRegionVal(R));
}
-inline BasicValueFactory &GRState::getBasicVals() const {
+inline BasicValueFactory &ProgramState::getBasicVals() const {
return getStateManager().getBasicVals();
}
-inline SymbolManager &GRState::getSymbolManager() const {
+inline SymbolManager &ProgramState::getSymbolManager() const {
return getStateManager().getSymbolManager();
}
template<typename T>
-const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
+const ProgramState *ProgramState::add(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().add<T>(this, K, get_context<T>());
}
template <typename T>
-typename GRStateTrait<T>::context_type GRState::get_context() const {
+typename ProgramStateTrait<T>::context_type ProgramState::get_context() const {
return getStateManager().get_context<T>();
}
template<typename T>
-const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
+const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().remove<T>(this, K, get_context<T>());
}
template<typename T>
-const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::context_type C) const {
+const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().remove<T>(this, K, C);
}
template <typename T>
-const GRState *GRState::remove() const {
+const ProgramState *ProgramState::remove() const {
return getStateManager().remove<T>(this);
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const {
return getStateManager().set<T>(this, K, E, get_context<T>());
}
template<typename T>
-const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
- typename GRStateTrait<T>::value_type E,
- typename GRStateTrait<T>::context_type C) const {
+const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().set<T>(this, K, E, C);
}
template <typename CB>
-CB GRState::scanReachableSymbols(SVal val) const {
+CB ProgramState::scanReachableSymbols(SVal val) const {
CB cb(this);
scanReachableSymbols(val, cb);
return cb;
}
template <typename CB>
-CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
+CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
template <typename CB>
-CB GRState::scanReachableSymbols(const MemRegion * const *beg,
+CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
const MemRegion * const *end) const {
CB cb(this);
scanReachableSymbols(beg, end, cb);
return cb;
}
+/// \class ScanReachableSymbols
+/// A Utility class that allows to visit the reachable symbols using a custom
+/// SymbolVisitor.
+class ScanReachableSymbols : public SubRegionMap::Visitor {
+ typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
+
+ VisitedItems visited;
+ const ProgramState *state;
+ SymbolVisitor &visitor;
+ llvm::OwningPtr<SubRegionMap> SRM;
+public:
+
+ ScanReachableSymbols(const ProgramState *st, SymbolVisitor& v)
+ : state(st), visitor(v) {}
+
+ bool scan(nonloc::CompoundVal val);
+ 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
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index de7b8684066f..b80d494b88cb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -1,4 +1,4 @@
-//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-//
+//ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*-
//
// The LLVM Compiler Infrastructure
//
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
//
// This file defines partial implementations of template specializations of
-// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
-// set/get methods for mapulating a GRState's generic data map.
+// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState
+// to implement set/get methods for mapulating a ProgramState's
+// generic data map.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_GR_GRSTATETRAIT_H
-#define LLVM_CLANG_GR_GRSTATETRAIT_H
+#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
+#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
namespace llvm {
class BumpPtrAllocator;
@@ -28,22 +29,22 @@ namespace llvm {
namespace clang {
namespace ento {
- template <typename T> struct GRStatePartialTrait;
+ template <typename T> struct ProgramStatePartialTrait;
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
- struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
typedef Data value_type;
typedef const value_type* lookup_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
- static inline void* MakeVoidPtr(data_type B) {
+ static inline void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
static lookup_type Lookup(data_type B, key_type K) {
@@ -57,15 +58,15 @@ namespace ento {
return F.remove(B, K);
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
@@ -74,16 +75,16 @@ namespace ento {
// Partial-specialization for ImmutableSet.
template <typename Key, typename Info>
- struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
typedef llvm::ImmutableSet<Key,Info> data_type;
typedef typename data_type::Factory& context_type;
typedef Key key_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
}
- static inline void* MakeVoidPtr(data_type B) {
+ static inline void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
@@ -99,15 +100,15 @@ namespace ento {
return B.contains(K);
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
@@ -115,7 +116,7 @@ namespace ento {
// Partial-specialization for ImmutableList.
template <typename T>
- struct GRStatePartialTrait< llvm::ImmutableList<T> > {
+ struct ProgramStatePartialTrait< llvm::ImmutableList<T> > {
typedef llvm::ImmutableList<T> data_type;
typedef T key_type;
typedef typename data_type::Factory& context_type;
@@ -128,33 +129,33 @@ namespace ento {
return L.contains(K);
}
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
: data_type(0);
}
- static inline void* MakeVoidPtr(data_type D) {
+ static inline void *MakeVoidPtr(data_type D) {
return (void*) D.getInternalPointer();
}
- static inline context_type MakeContext(void* p) {
+ static inline context_type MakeContext(void *p) {
return *((typename data_type::Factory*) p);
}
- static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
return new typename data_type::Factory(Alloc);
}
- static void DeleteContext(void* Ctx) {
+ static void DeleteContext(void *Ctx) {
delete (typename data_type::Factory*) Ctx;
}
};
// Partial specialization for bool.
- template <> struct GRStatePartialTrait<bool> {
+ template <> struct ProgramStatePartialTrait<bool> {
typedef bool data_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
@@ -164,10 +165,10 @@ namespace ento {
};
// Partial specialization for unsigned.
- template <> struct GRStatePartialTrait<unsigned> {
+ template <> struct ProgramStatePartialTrait<unsigned> {
typedef unsigned data_type;
- static inline data_type MakeData(void* const* p) {
+ static inline data_type MakeData(void *const* p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 65eabea24077..17233e194e6d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -25,7 +25,7 @@ namespace clang {
namespace ento {
-class GRState;
+class ProgramState;
class SValBuilder {
protected:
@@ -40,7 +40,7 @@ protected:
/// Manages the creation of memory regions.
MemRegionManager MemMgr;
- GRStateManager &StateMgr;
+ ProgramStateManager &StateMgr;
/// The scalar type to use for array indices.
const QualType ArrayIndexTy;
@@ -56,7 +56,7 @@ public:
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
- GRStateManager &stateMgr)
+ ProgramStateManager &stateMgr)
: Context(context), BasicVals(context, alloc),
SymMgr(context, BasicVals, alloc),
MemMgr(context, alloc),
@@ -72,29 +72,29 @@ public:
virtual SVal evalComplement(NonLoc val) = 0;
- virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal val) = 0;
+ virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal val) = 0;
- SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type);
- DefinedOrUnknownSVal evalEQ(const GRState *state, DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal evalEQ(const ProgramState *state, DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs);
ASTContext &getContext() { return Context; }
const ASTContext &getContext() const { return Context; }
- GRStateManager &getStateManager() { return StateMgr; }
+ ProgramStateManager &getStateManager() { return StateMgr; }
QualType getConditionType() const {
return getContext().IntTy;
@@ -115,14 +115,14 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt* stmt, QualType type,
+ const SymbolConjured* getConjuredSymbol(const Stmt *stmt, QualType type,
unsigned visitCount,
- const void* symbolTag = 0) {
+ const void *symbolTag = 0) {
return SymMgr.getConjuredSymbol(stmt, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr* expr, unsigned visitCount,
- const void* symbolTag = 0) {
+ const SymbolConjured* getConjuredSymbol(const Expr *expr, unsigned visitCount,
+ const void *symbolTag = 0) {
return SymMgr.getConjuredSymbol(expr, visitCount, symbolTag);
}
@@ -130,7 +130,7 @@ public:
DefinedOrUnknownSVal makeZeroVal(QualType type);
/// getRegionValueSymbolVal - make a unique symbol for value of region.
- DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *region);
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
const Expr *expr, unsigned count);
@@ -139,7 +139,7 @@ public:
unsigned count);
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
- SymbolRef parentSymbol, const TypedRegion *region);
+ SymbolRef parentSymbol, const TypedValueRegion *region);
DefinedSVal getMetadataSymbolVal(
const void *symbolTag, const MemRegion *region,
@@ -154,7 +154,8 @@ public:
return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
}
- NonLoc makeLazyCompoundVal(const StoreRef &store, const TypedRegion *region) {
+ NonLoc makeLazyCompoundVal(const StoreRef &store,
+ const TypedValueRegion *region) {
return nonloc::LazyCompoundVal(
BasicVals.getLazyCompoundValData(store, region));
}
@@ -254,7 +255,7 @@ public:
SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
ASTContext &context,
- GRStateManager &stateMgr);
+ ProgramStateManager &stateMgr);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 0d430794e76c..5827b0042a5d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -15,14 +15,10 @@
#ifndef LLVM_CLANG_GR_RVALUE_H
#define LLVM_CLANG_GR_RVALUE_H
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
-namespace llvm {
- class raw_ostream;
-}
-
//==------------------------------------------------------------------------==//
// Base SVal types.
//==------------------------------------------------------------------------==//
@@ -33,12 +29,12 @@ namespace ento {
class CompoundValData;
class LazyCompoundValData;
-class GRState;
+class ProgramState;
class BasicValueFactory;
class MemRegion;
class TypedRegion;
class MemRegionManager;
-class GRStateManager;
+class ProgramStateManager;
class SValBuilder;
/// SVal - This represents a symbolic expression, which can be either
@@ -57,16 +53,16 @@ public:
enum { BaseBits = 2, BaseMask = 0x3 };
protected:
- const void* Data;
+ const void *Data;
/// The lowest 2 bits are a BaseKind (0 -- 3).
/// The higher bits are an unsigned "kind" value.
unsigned Kind;
- explicit SVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit SVal(const void *d, bool isLoc, unsigned ValKind)
: Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
- explicit SVal(BaseKind k, const void* D = NULL)
+ explicit SVal(BaseKind k, const void *D = NULL)
: Data(D), Kind(k) {}
public:
@@ -74,7 +70,7 @@ public:
~SVal() {}
/// BufferTy - A temporary buffer to hold a set of SVals.
- typedef llvm::SmallVector<SVal,5> BufferTy;
+ typedef SmallVector<SVal,5> BufferTy;
inline unsigned getRawKind() const { return Kind; }
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
@@ -123,7 +119,7 @@ public:
/// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
/// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
/// Otherwise return 0.
- const FunctionDecl* getAsFunctionDecl() const;
+ const FunctionDecl *getAsFunctionDecl() const;
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return NULL.
@@ -142,22 +138,22 @@ public:
const MemRegion *getAsRegion() const;
- void dumpToStream(llvm::raw_ostream& OS) const;
+ void dumpToStream(raw_ostream &OS) const;
void dump() const;
// Iterators.
class symbol_iterator {
- llvm::SmallVector<const SymExpr*, 5> itr;
+ SmallVector<const SymExpr*, 5> itr;
void expand();
public:
symbol_iterator() {}
- symbol_iterator(const SymExpr* SE);
+ symbol_iterator(const SymExpr *SE);
- symbol_iterator& operator++();
+ symbol_iterator &operator++();
SymbolRef operator*();
- bool operator==(const symbol_iterator& X) const;
- bool operator!=(const symbol_iterator& X) const;
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
};
symbol_iterator symbol_begin() const {
@@ -178,13 +174,13 @@ public:
class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
- UndefinedVal(const void* D) : SVal(UndefinedKind, D) {}
+ UndefinedVal(const void *D) : SVal(UndefinedKind, D) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UndefinedKind;
}
- const void* getData() const { return Data; }
+ const void *getData() const { return Data; }
};
class DefinedOrUnknownSVal : public SVal {
@@ -195,7 +191,7 @@ private:
bool isValid() const;
protected:
- explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
: SVal(d, isLoc, ValKind) {}
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
@@ -225,7 +221,7 @@ private:
bool isUnknownOrUndef() const;
bool isValid() const;
protected:
- explicit DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
+ explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
: DefinedOrUnknownSVal(d, isLoc, ValKind) {}
public:
// Implement isa<T> support.
@@ -236,11 +232,11 @@ public:
class NonLoc : public DefinedSVal {
protected:
- explicit NonLoc(unsigned SubKind, const void* d)
+ explicit NonLoc(unsigned SubKind, const void *d)
: DefinedSVal(d, false, SubKind) {}
public:
- void dumpToStream(llvm::raw_ostream& Out) const;
+ void dumpToStream(raw_ostream &Out) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
@@ -250,11 +246,11 @@ public:
class Loc : public DefinedSVal {
protected:
- explicit Loc(unsigned SubKind, const void* D)
+ explicit Loc(unsigned SubKind, const void *D)
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
- void dumpToStream(llvm::raw_ostream& Out) const;
+ void dumpToStream(raw_ostream &Out) const;
Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
@@ -533,7 +529,7 @@ public:
} // end clang namespace
namespace llvm {
-static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
clang::ento::SVal V) {
V.dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index cdbdf64515b4..a688d7f21979 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -29,20 +29,20 @@ class StackFrameContext;
namespace ento {
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class SubRegionMap;
class StoreManager {
protected:
SValBuilder &svalBuilder;
- GRStateManager &StateMgr;
+ ProgramStateManager &StateMgr;
/// MRMgr - Manages region objects associated with this StoreManager.
MemRegionManager &MRMgr;
ASTContext &Ctx;
- StoreManager(GRStateManager &stateMgr);
+ StoreManager(ProgramStateManager &stateMgr);
public:
virtual ~StoreManager() {}
@@ -60,7 +60,7 @@ public:
/// \param[in] state 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 GRState object that contains the same bindings as
+ /// \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;
@@ -73,7 +73,7 @@ public:
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
virtual StoreRef BindCompoundLiteral(Store store,
- const CompoundLiteralExpr* cl,
+ const CompoundLiteralExpr *cl,
const LocationContext *LC, SVal v) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
@@ -97,16 +97,16 @@ public:
return svalBuilder.makeLoc(MRMgr.getStringRegion(S));
}
- Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
- virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
+ virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
return getLValueFieldOrIvar(decl, base);
}
- virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
+ virtual SVal getLValueField(const FieldDecl *D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
}
@@ -114,7 +114,7 @@ public:
// FIXME: This should soon be eliminated altogether; clients should deal with
// region extents directly.
- virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ virtual DefinedOrUnknownSVal getSizeInElements(const ProgramState *state,
const MemRegion *region,
QualType EleTy) {
return UnknownVal();
@@ -130,12 +130,12 @@ public:
}
class CastResult {
- const GRState *state;
+ const ProgramState *state;
const MemRegion *region;
public:
- const GRState *getState() const { return state; }
+ const ProgramState *getState() const { return state; }
const MemRegion* getRegion() const { return region; }
- CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
+ CastResult(const ProgramState *s, const MemRegion* r = 0) : state(s), region(r){}
};
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
@@ -146,13 +146,15 @@ public:
const MemRegion *castRegion(const MemRegion *region, QualType CastToTy);
virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
+ SymbolReaper& SymReaper) = 0;
virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
+ virtual bool includedInBindings(Store store,
+ const MemRegion *region) const = 0;
+
/// If the StoreManager supports it, increment the reference count of
/// the specified Store object.
virtual void incrementReferenceCount(Store store) {}
@@ -163,7 +165,7 @@ public:
virtual void decrementReferenceCount(Store store) {}
typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
- typedef llvm::SmallVector<const MemRegion *, 8> InvalidatedRegions;
+ typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
/// invalidateRegions - Clears out the specified regions from the store,
/// marking their values as unknown. Depending on the store, this may also
@@ -185,19 +187,18 @@ public:
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual StoreRef invalidateRegions(Store store,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
+ ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
InvalidatedSymbols &IS,
bool invalidateGlobals,
- InvalidatedRegions *Regions) = 0;
+ InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
- virtual StoreRef enterStackFrame(const GRState *state,
+ virtual StoreRef enterStackFrame(const ProgramState *state,
const StackFrameContext *frame);
- virtual void print(Store store, llvm::raw_ostream& Out,
+ virtual void print(Store store, raw_ostream &Out,
const char* nl, const char *sep) = 0;
class BindingsHandler {
@@ -217,11 +218,11 @@ protected:
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
- SVal CastRetrievedVal(SVal val, const TypedRegion *region, QualType castTy,
- bool performTestOnly = true);
+ SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
+ QualType castTy, bool performTestOnly = true);
private:
- SVal getLValueFieldOrIvar(const Decl* decl, SVal base);
+ SVal getLValueFieldOrIvar(const Decl *decl, SVal base);
};
@@ -269,11 +270,9 @@ public:
virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
};
-// FIXME: Do we need to pass GRStateManager anymore?
-StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
-StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
-StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
-StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
+// FIXME: Do we need to pass ProgramStateManager anymore?
+StoreManager *CreateRegionStoreManager(ProgramStateManager& StMgr);
+StoreManager *CreateFieldsOnlyRegionStoreManager(ProgramStateManager& StMgr);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
index 0662eadc93c3..d5ba003a6915 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -23,7 +23,7 @@ namespace ento {
/// locations to values. At a high-level, it represents the symbolic
/// memory model. Different subclasses of StoreManager may choose
/// different types to represent the locations and values.
-typedef const void* Store;
+typedef const void *Store;
class StoreManager;
@@ -44,6 +44,7 @@ public:
~StoreRef();
Store getStore() const { return store; }
+ const StoreManager &getStoreManager() const { return mgr; }
};
}}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 1f6ea3d8c732..ae212bcf5ddf 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -30,8 +30,8 @@ template <typename PP> class GenericNodeBuilder;
class AnalysisManager;
class ExplodedNodeSet;
class ExplodedNode;
-class GRState;
-class GRStateManager;
+class ProgramState;
+class ProgramStateManager;
class BlockCounter;
class StmtNodeBuilder;
class BranchNodeBuilder;
@@ -46,11 +46,11 @@ class SubEngine {
public:
virtual ~SubEngine() {}
- virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
+ virtual const ProgramState *getInitialState(const LocationContext *InitLoc) = 0;
virtual AnalysisManager &getAnalysisManager() = 0;
- virtual GRStateManager &getStateManager() = 0;
+ virtual ProgramStateManager &getStateManager() = 0;
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
@@ -64,7 +64,7 @@ public:
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
- virtual void processBranch(const Stmt* Condition, const Stmt* Term,
+ virtual void processBranch(const Stmt *Condition, const Stmt *Term,
BranchNodeBuilder& builder) = 0;
/// Called by CoreEngine. Used to generate successor
@@ -87,28 +87,32 @@ public:
/// Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
- virtual const GRState* processAssume(const GRState *state,
+ virtual const ProgramState *processAssume(const ProgramState *state,
SVal cond, bool assumption) = 0;
- /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a
+ /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- virtual bool wantsRegionChangeUpdate(const GRState* state) = 0;
+ virtual bool wantsRegionChangeUpdate(const ProgramState *state) = 0;
- /// processRegionChanges - Called by GRStateManager whenever a change is made
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- virtual const GRState *
- processRegionChanges(const GRState *state,
+ virtual const ProgramState *
+ processRegionChanges(const ProgramState *state,
const StoreManager::InvalidatedSymbols *invalidated,
- const MemRegion* const *Begin,
- const MemRegion* const *End) = 0;
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions) = 0;
- inline const GRState *
- processRegionChange(const GRState* state,
+ inline const ProgramState *
+ processRegionChange(const ProgramState *state,
const MemRegion* MR) {
- return processRegionChanges(state, 0, &MR, &MR+1);
+ return processRegionChanges(state, 0, MR, MR);
}
+ /// printState - Called by ProgramStateManager to print checker-specific data.
+ virtual void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) = 0;
+
/// Called by CoreEngine when the analysis worklist is either empty or the
// maximum number of analysis steps have been reached.
virtual void processEndWorklist(bool hasWorkRemaining) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index ad173bb43536..0d6e18eb3cc8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -18,13 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
namespace llvm {
class BumpPtrAllocator;
-class raw_ostream;
}
namespace clang {
@@ -35,15 +37,15 @@ namespace ento {
class BasicValueFactory;
class MemRegion;
class SubRegion;
- class TypedRegion;
+ class TypedValueRegion;
class VarRegion;
class SymExpr : public llvm::FoldingSetNode {
public:
- enum Kind { BEGIN_SYMBOLS,
- RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
+ enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
MetadataKind,
- END_SYMBOLS,
+ BEGIN_SYMBOLS = RegionValueKind,
+ END_SYMBOLS = MetadataKind,
SymIntKind, SymSymKind };
private:
Kind K;
@@ -58,7 +60,7 @@ public:
void dump() const;
- virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
+ virtual void dumpToStream(raw_ostream &os) const = 0;
virtual QualType getType(ASTContext&) const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
@@ -82,25 +84,26 @@ public:
SymbolID getSymbolID() const { return Sym; }
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
Kind k = SE->getKind();
- return k > BEGIN_SYMBOLS && k < END_SYMBOLS;
+ return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
}
};
typedef const SymbolData* SymbolRef;
+typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
-// A symbol representing the value of a MemRegion.
+/// A symbol representing the value of a MemRegion.
class SymbolRegionValue : public SymbolData {
- const TypedRegion *R;
+ const TypedValueRegion *R;
public:
- SymbolRegionValue(SymbolID sym, const TypedRegion *r)
+ SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
: SymbolData(RegionValueKind, sym), R(r) {}
- const TypedRegion* getRegion() const { return R; }
+ const TypedValueRegion* getRegion() const { return R; }
- static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
+ static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
profile.AddInteger((unsigned) RegionValueKind);
profile.AddPointer(R);
}
@@ -109,39 +112,39 @@ public:
Profile(profile, R);
}
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
QualType getType(ASTContext&) const;
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == RegionValueKind;
}
};
-// A symbol representing the result of an expression.
+/// A symbol representing the result of an expression.
class SymbolConjured : public SymbolData {
- const Stmt* S;
+ const Stmt *S;
QualType T;
unsigned Count;
- const void* SymbolTag;
+ const void *SymbolTag;
public:
- SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count,
- const void* symbolTag)
+ SymbolConjured(SymbolID sym, const Stmt *s, QualType t, unsigned count,
+ const void *symbolTag)
: SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
SymbolTag(symbolTag) {}
- const Stmt* getStmt() const { return S; }
+ const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
- const void* getTag() const { return SymbolTag; }
+ const void *getTag() const { return SymbolTag; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
- static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
- QualType T, unsigned Count, const void* SymbolTag) {
+ static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
+ QualType T, unsigned Count, const void *SymbolTag) {
profile.AddInteger((unsigned) ConjuredKind);
profile.AddPointer(S);
profile.Add(T);
@@ -154,30 +157,30 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == ConjuredKind;
}
};
-// A symbol representing the value of a MemRegion whose parent region has
-// symbolic value.
+/// A symbol representing the value of a MemRegion whose parent region has
+/// symbolic value.
class SymbolDerived : public SymbolData {
SymbolRef parentSymbol;
- const TypedRegion *R;
+ const TypedValueRegion *R;
public:
- SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
+ SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
: SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
SymbolRef getParentSymbol() const { return parentSymbol; }
- const TypedRegion *getRegion() const { return R; }
+ const TypedValueRegion *getRegion() const { return R; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
- const TypedRegion *r) {
+ const TypedValueRegion *r) {
profile.AddInteger((unsigned) DerivedKind);
profile.AddPointer(r);
profile.AddPointer(parent);
@@ -188,7 +191,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == DerivedKind;
}
};
@@ -207,7 +210,7 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
profile.AddInteger((unsigned) ExtentKind);
@@ -219,7 +222,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == ExtentKind;
}
};
@@ -230,23 +233,23 @@ public:
/// Intended for use by checkers.
class SymbolMetadata : public SymbolData {
const MemRegion* R;
- const Stmt* S;
+ const Stmt *S;
QualType T;
unsigned Count;
- const void* Tag;
+ const void *Tag;
public:
- SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt* s, QualType t,
- unsigned count, const void* tag)
+ SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
+ unsigned count, const void *tag)
: SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
const MemRegion *getRegion() const { return R; }
- const Stmt* getStmt() const { return S; }
+ const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
- const void* getTag() const { return Tag; }
+ const void *getTag() const { return Tag; }
QualType getType(ASTContext&) const;
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
@@ -264,12 +267,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == MetadataKind;
}
};
-// SymIntExpr - Represents symbolic expression like 'x' + 3.
+/// SymIntExpr - Represents symbolic expression like 'x' + 3.
class SymIntExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
@@ -283,11 +286,11 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext& C) const { return T; }
+ QualType getType(ASTContext &C) const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
@@ -307,12 +310,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == SymIntKind;
}
};
-// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
+/// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
class SymSymExpr : public SymExpr {
const SymExpr *LHS;
BinaryOperator::Opcode Op;
@@ -330,9 +333,9 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext& C) const { return T; }
+ QualType getType(ASTContext &C) const { return T; }
- void dumpToStream(llvm::raw_ostream &os) const;
+ void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
@@ -348,48 +351,58 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr* SE) {
+ static inline bool classof(const SymExpr *SE) {
return SE->getKind() == SymSymKind;
}
};
class SymbolManager {
typedef llvm::FoldingSet<SymExpr> DataSetTy;
+ typedef llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy*> SymbolDependTy;
+
DataSetTy DataSet;
+ /// Stores the extra dependencies between symbols: the data should be kept
+ /// alive as long as the key is live.
+ SymbolDependTy SymbolDependencies;
unsigned SymbolCounter;
llvm::BumpPtrAllocator& BPAlloc;
BasicValueFactory &BV;
- ASTContext& Ctx;
+ ASTContext &Ctx;
public:
- SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+ SymbolManager(ASTContext &ctx, BasicValueFactory &bv,
llvm::BumpPtrAllocator& bpalloc)
- : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
+ : SymbolDependencies(16), SymbolCounter(0),
+ BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
~SymbolManager();
static bool canSymbolicate(QualType T);
- /// Make a unique symbol for MemRegion R according to its kind.
- const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R);
+ /// \brief Make a unique symbol for MemRegion R according to its kind.
+ const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
- const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ const SymbolConjured* getConjuredSymbol(const Stmt *E, QualType T,
unsigned VisitCount,
- const void* SymbolTag = 0);
+ const void *SymbolTag = 0);
- const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
- const void* SymbolTag = 0) {
+ const SymbolConjured* getConjuredSymbol(const Expr *E, unsigned VisitCount,
+ const void *SymbolTag = 0) {
return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
- const TypedRegion *R);
+ const TypedValueRegion *R);
const SymbolExtent *getExtentSymbol(const SubRegion *R);
- const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt* S,
+ /// \brief Creates a metadata symbol associated with a specific region.
+ ///
+ /// VisitCount can be used to differentiate regions corresponding to
+ /// different loop iterations, thus, making the symbol path-dependent.
+ const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt *S,
QualType T, unsigned VisitCount,
- const void* SymbolTag = 0);
+ const void *SymbolTag = 0);
const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t);
@@ -406,23 +419,43 @@ public:
return SE->getType(Ctx);
}
+ /// \brief Add artificial symbol dependency.
+ ///
+ /// The dependent symbol should stay alive as long as the primary is alive.
+ void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent);
+
+ const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary);
+
ASTContext &getContext() { return Ctx; }
BasicValueFactory &getBasicVals() { return BV; }
};
class SymbolReaper {
- typedef llvm::DenseSet<SymbolRef> SetTy;
+ enum SymbolStatus {
+ NotProcessed,
+ HaveMarkedDependents
+ };
- SetTy TheLiving;
- SetTy MetadataInUse;
- SetTy TheDead;
+ typedef llvm::DenseSet<SymbolRef> SymbolSetTy;
+ typedef llvm::DenseMap<SymbolRef, SymbolStatus> SymbolMapTy;
+ typedef llvm::DenseSet<const MemRegion *> RegionSetTy;
+
+ SymbolMapTy TheLiving;
+ SymbolSetTy MetadataInUse;
+ SymbolSetTy TheDead;
+
+ RegionSetTy RegionRoots;
+
const LocationContext *LCtx;
const Stmt *Loc;
SymbolManager& SymMgr;
+ StoreRef reapedStore;
+ llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache;
public:
- SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr)
- : LCtx(ctx), Loc(s), SymMgr(symmgr) {}
+ SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
+ StoreManager &storeMgr)
+ : LCtx(ctx), Loc(s), SymMgr(symmgr), reapedStore(0, storeMgr) {}
~SymbolReaper() {}
@@ -430,48 +463,71 @@ public:
const Stmt *getCurrentStatement() const { return Loc; }
bool isLive(SymbolRef sym);
+ bool isLiveRegion(const MemRegion *region);
bool isLive(const Stmt *ExprVal) const;
- bool isLive(const VarRegion *VR) const;
+ bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
- // markLive - Unconditionally marks a symbol as live. This should never be
- // used by checkers, only by the state infrastructure such as the store and
- // environment. Checkers should instead use metadata symbols and markInUse.
+ /// \brief Unconditionally marks a symbol as live.
+ ///
+ /// This should never be
+ /// used by checkers, only by the state infrastructure such as the store and
+ /// environment. Checkers should instead use metadata symbols and markInUse.
void markLive(SymbolRef sym);
- // markInUse - Marks a symbol as important to a checker. For metadata symbols,
- // this will keep the symbol alive as long as its associated region is also
- // live. For other symbols, this has no effect; checkers are not permitted
- // to influence the life of other symbols. This should be used before any
- // symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
+ /// \brief Marks a symbol as important to a checker.
+ ///
+ /// For metadata symbols,
+ /// this will keep the symbol alive as long as its associated region is also
+ /// live. For other symbols, this has no effect; checkers are not permitted
+ /// to influence the life of other symbols. This should be used before any
+ /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
void markInUse(SymbolRef sym);
- // maybeDead - If a symbol is known to be live, marks the symbol as live.
- // Otherwise, if the symbol cannot be proven live, it is marked as dead.
- // Returns true if the symbol is dead, false if live.
+ /// \brief If a symbol is known to be live, marks the symbol as live.
+ ///
+ /// Otherwise, if the symbol cannot be proven live, it is marked as dead.
+ /// Returns true if the symbol is dead, false if live.
bool maybeDead(SymbolRef sym);
- typedef SetTy::const_iterator dead_iterator;
+ typedef SymbolSetTy::const_iterator dead_iterator;
dead_iterator dead_begin() const { return TheDead.begin(); }
dead_iterator dead_end() const { return TheDead.end(); }
bool hasDeadSymbols() const {
return !TheDead.empty();
}
-
- /// isDead - Returns whether or not a symbol has been confirmed dead. This
- /// should only be called once all marking of dead symbols has completed.
- /// (For checkers, this means only in the evalDeadSymbols callback.)
+
+ typedef RegionSetTy::const_iterator region_iterator;
+ region_iterator region_begin() const { return RegionRoots.begin(); }
+ region_iterator region_end() const { return RegionRoots.end(); }
+
+ /// \brief Returns whether or not a symbol has been confirmed dead.
+ ///
+ /// This should only be called once all marking of dead symbols has completed.
+ /// (For checkers, this means only in the evalDeadSymbols callback.)
bool isDead(SymbolRef sym) const {
return TheDead.count(sym);
}
+
+ void markLive(const MemRegion *region);
+
+ /// \brief Set to the value of the symbolic store after
+ /// StoreManager::removeDeadBindings has been called.
+ void setReapedStore(StoreRef st) { reapedStore = st; }
+
+private:
+ /// Mark the symbols dependent on the input symbol as live.
+ void markDependentsLive(SymbolRef sym);
};
class SymbolVisitor {
public:
- // VisitSymbol - A visitor method invoked by
- // GRStateManager::scanReachableSymbols. The method returns \c true if
- // symbols should continue be scanned and \c false otherwise.
+ /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols.
+ ///
+ /// The method returns \c true if symbols should continue be scanned and \c
+ /// false otherwise.
virtual bool VisitSymbol(SymbolRef sym) = 0;
+ virtual bool VisitMemRegion(const MemRegion *region) { return true; }
virtual ~SymbolVisitor();
};
@@ -480,7 +536,7 @@ public:
} // end clang namespace
namespace llvm {
-static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+static inline raw_ostream &operator<<(raw_ostream &os,
const clang::ento::SymExpr *SE) {
SE->dumpToStream(os);
return os;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
deleted file mode 100644
index 23ed2be8c7a4..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//== TransferFuncs.h - Path-Sens. Transfer Functions Interface ---*- 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 TransferFuncs, which provides a base-class that
-// defines an interface for transfer functions used by ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
-#define LLVM_CLANG_GR_TRANSFERFUNCS
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
-#include <vector>
-
-namespace clang {
-class ObjCMessageExpr;
-
-namespace ento {
-class ExplodedNode;
-class ExplodedNodeSet;
-class EndOfFunctionNodeBuilder;
-class ExprEngine;
-class StmtNodeBuilder;
-class StmtNodeBuilderRef;
-
-class TransferFuncs {
-public:
- TransferFuncs() {}
- virtual ~TransferFuncs() {}
-
- virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
- virtual void RegisterChecks(ExprEngine& Eng) {}
-
-
- // Calls.
-
- virtual void evalCall(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const CallExpr* CE, SVal L,
- ExplodedNode* Pred) {}
-
- virtual void evalObjCMessage(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ObjCMessage msg,
- ExplodedNode* Pred,
- const GRState *state) {}
-
- // Stores.
-
- virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {}
-
- // End-of-path and dead symbol notification.
-
- virtual void evalEndPath(ExprEngine& Engine,
- EndOfFunctionNodeBuilder& Builder) {}
-
-
- virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- ExplodedNode* Pred,
- const GRState* state,
- SymbolReaper& SymReaper) {}
-
- // Return statements.
- virtual void evalReturn(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ReturnStmt* S,
- ExplodedNode* Pred) {}
-
- // Assumptions.
- virtual const GRState* evalAssume(const GRState *state,
- SVal Cond, bool Assumption) {
- return state;
- }
-};
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 6bc9fe56f8d6..fa340753e5b7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -28,20 +28,20 @@ class ExplodedNode;
class ExplodedNodeImpl;
class WorkListUnit {
- ExplodedNode* node;
+ ExplodedNode *node;
BlockCounter counter;
- const CFGBlock* block;
+ const CFGBlock *block;
unsigned blockIdx; // This is the index of the next statement.
public:
- WorkListUnit(ExplodedNode* N, BlockCounter C,
- const CFGBlock* B, unsigned idx)
+ WorkListUnit(ExplodedNode *N, BlockCounter C,
+ const CFGBlock *B, unsigned idx)
: node(N),
counter(C),
block(B),
blockIdx(idx) {}
- explicit WorkListUnit(ExplodedNode* N, BlockCounter C)
+ explicit WorkListUnit(ExplodedNode *N, BlockCounter C)
: node(N),
counter(C),
block(NULL),