aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h13
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h1
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp117
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp32
10 files changed, 110 insertions, 90 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 11b665a445..268c85b068 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -338,6 +338,10 @@ public:
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,
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index fdc6055bb4..db94b81d65 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -267,6 +267,17 @@ public:
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.
//===----------------------------------------------------------------------===//
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index b2c1c4a53a..fa46ebbaf3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -195,6 +195,10 @@ public:
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions);
+ /// 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(); }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 7ec3965fa6..c83792ce64 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -332,14 +332,6 @@ public:
return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key);
}
- // State pretty-printing.
- class Printer {
- public:
- virtual ~Printer() {}
- virtual void Print(raw_ostream &Out, const ProgramState *state,
- const char* nl, const char* sep) = 0;
- };
-
// Pretty-printing.
void print(raw_ostream &Out, CFG &C, const char *nl = "\n",
const char *sep = "") const;
@@ -404,7 +396,6 @@ public:
class ProgramStateManager {
friend class ProgramState;
- friend class ExprEngine; // FIXME: Remove.
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine *Eng; /* Can be null. */
@@ -418,10 +409,6 @@ private:
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
- /// Printers - A set of printer objects used for pretty-printing a ProgramState.
- /// ProgramStateManager owns these objects.
- std::vector<ProgramState::Printer*> Printers;
-
/// StateSet - FoldingSet containing all the states created for analyzing
/// a particular function. This is used to unique states.
llvm::FoldingSet<ProgramState> StateSet;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index f5a3d4c1be..ae212bcf5d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -109,6 +109,10 @@ public:
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/TransferFuncs.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
index 35f680ba86..a82fd26719 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h
@@ -36,7 +36,6 @@ public:
TransferFuncs() {}
virtual ~TransferFuncs() {}
- virtual void RegisterPrinters(std::vector<ProgramState::Printer*>& Printers) {}
virtual void RegisterChecks(ExprEngine& Eng) {}
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 7991071a54..a38c450148 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -255,7 +255,7 @@ public:
void RefVal::print(raw_ostream &Out) const {
if (!T.isNull())
- Out << "Tracked Type:" << T.getAsString() << '\n';
+ Out << "Tracked " << T.getAsString() << '/';
switch (getKind()) {
default: assert(false);
@@ -1585,14 +1585,6 @@ namespace {
class CFRefCount : public TransferFuncs {
public:
- class BindingsPrinter : public ProgramState::Printer {
- public:
- virtual void Print(raw_ostream &Out,
- const ProgramState *state,
- const char* nl,
- const char* sep);
- };
-
const LangOptions& LOpts;
const bool GCEnabled;
@@ -1601,60 +1593,12 @@ public:
: LOpts(lopts), GCEnabled(gcenabled) {}
void RegisterChecks(ExprEngine &Eng);
-
- virtual void RegisterPrinters(std::vector<ProgramState::Printer*>& Printers) {
- Printers.push_back(new BindingsPrinter());
- }
const LangOptions& getLangOptions() const { return LOpts; }
};
} // end anonymous namespace
-static void PrintPool(raw_ostream &Out,
- SymbolRef Sym,
- const ProgramState *state) {
- Out << ' ';
- if (Sym)
- Out << Sym->getSymbolID();
- else
- Out << "<pool>";
- Out << ":{";
-
- // Get the contents of the pool.
- if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym))
- for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J)
- Out << '(' << J.getKey() << ',' << J.getData() << ')';
-
- Out << '}';
-}
-
-void CFRefCount::BindingsPrinter::Print(raw_ostream &Out,
- const ProgramState *state,
- const char* nl, const char* sep) {
-
- RefBindings B = state->get<RefBindings>();
-
- if (!B.isEmpty())
- Out << sep << nl;
-
- for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
- Out << (*I).first << " : ";
- (*I).second.print(Out);
- Out << nl;
- }
-
- // Print the autorelease stack.
- Out << sep << nl << "AR pool stack:";
- ARStack stack = state->get<AutoreleaseStack>();
-
- PrintPool(Out, SymbolRef(), state); // Print the caller's pool.
- for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I)
- PrintPool(Out, *I, state);
-
- Out << nl;
-}
-
//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//
@@ -2543,6 +2487,9 @@ public:
}
}
+ void printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) const;
+
void checkBind(SVal loc, SVal val, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -3623,6 +3570,62 @@ void RetainReleaseChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
//===----------------------------------------------------------------------===//
+// Debug printing of refcount bindings and autorelease pools.
+//===----------------------------------------------------------------------===//
+
+static void PrintPool(raw_ostream &Out, SymbolRef Sym,
+ const ProgramState *State) {
+ Out << ' ';
+ if (Sym)
+ Out << Sym->getSymbolID();
+ else
+ Out << "<pool>";
+ Out << ":{";
+
+ // Get the contents of the pool.
+ if (const ARCounts *Cnts = State->get<AutoreleasePoolContents>(Sym))
+ for (ARCounts::iterator I = Cnts->begin(), E = Cnts->end(); I != E; ++I)
+ Out << '(' << I.getKey() << ',' << I.getData() << ')';
+
+ Out << '}';
+}
+
+bool UsesAutorelease(const ProgramState *state) {
+ // A state uses autorelease if it allocated an autorelease pool or if it has
+ // objects in the caller's autorelease pool.
+ return !state->get<AutoreleaseStack>().isEmpty() ||
+ state->get<AutoreleasePoolContents>(SymbolRef());
+}
+
+void RetainReleaseChecker::printState(raw_ostream &Out,
+ const ProgramState *State,
+ const char *NL, const char *Sep) const {
+
+ RefBindings B = State->get<RefBindings>();
+
+ if (!B.isEmpty())
+ Out << Sep << NL;
+
+ for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ Out << I->first << " : ";
+ I->second.print(Out);
+ Out << NL;
+ }
+
+ // Print the autorelease stack.
+ if (UsesAutorelease(State)) {
+ Out << Sep << NL << "AR pool stack:";
+ ARStack Stack = State->get<AutoreleaseStack>();
+
+ PrintPool(Out, SymbolRef(), State); // Print the caller's pool.
+ for (ARStack::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I)
+ PrintPool(Out, *I, State);
+
+ Out << NL;
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 196376c340..3e451fdbbb 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -426,6 +426,14 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit(
EndOfTranslationUnitCheckers[i](TU, mgr, BR);
}
+void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
+ const ProgramState *State,
+ const char *NL, const char *Sep) {
+ for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
+ I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
+ I->second->printState(Out, State, NL, Sep);
+}
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 1a32d43d4d..9dd2884578 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -67,7 +67,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
- TF->RegisterPrinters(getStateManager().Printers);
if (mgr.shouldEagerlyTrimExplodedGraph()) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
@@ -189,6 +188,11 @@ ExprEngine::processRegionChanges(const ProgramState *state,
Explicits, Regions);
}
+void ExprEngine::printState(raw_ostream &Out, const ProgramState *State,
+ const char *NL, const char *Sep) {
+ getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep);
+}
+
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 54a626b676..54da7b5170 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -51,10 +51,6 @@ ProgramState::~ProgramState() {
}
ProgramStateManager::~ProgramStateManager() {
- for (std::vector<ProgramState::Printer*>::iterator I=Printers.begin(),
- E=Printers.end(); I!=E; ++I)
- delete *I;
-
for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
I!=E; ++I)
I->second.second(I->second.first);
@@ -389,11 +385,11 @@ static bool IsEnvLoc(const Stmt *S) {
return (bool) (((uintptr_t) S) & 0x1);
}
-void ProgramState::print(raw_ostream &Out, CFG &C, const char* nl,
- const char* sep) const {
+void ProgramState::print(raw_ostream &Out, CFG &C,
+ const char *NL, const char *Sep) const {
// Print the store.
ProgramStateManager &Mgr = getStateManager();
- Mgr.getStoreManager().print(getStore(), Out, nl, sep);
+ Mgr.getStoreManager().print(getStore(), Out, NL, Sep);
// Print Subexpression bindings.
bool isFirst = true;
@@ -404,10 +400,11 @@ void ProgramState::print(raw_ostream &Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Sub-Expressions:" << nl;
+ Out << NL << NL << "Sub-Expressions:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
@@ -423,10 +420,11 @@ void ProgramState::print(raw_ostream &Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Block-level Expressions:" << nl;
+ Out << NL << NL << "Block-level Expressions:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
Out << " (" << (void*) I.getKey() << ") ";
LangOptions LO; // FIXME.
@@ -442,10 +440,11 @@ void ProgramState::print(raw_ostream &Out, CFG &C, const char* nl,
continue;
if (isFirst) {
- Out << nl << nl << "Load/store locations:" << nl;
+ Out << NL << NL << "Load/store locations:" << NL;
isFirst = false;
+ } else {
+ Out << NL;
}
- else { Out << nl; }
const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1));
@@ -455,13 +454,10 @@ void ProgramState::print(raw_ostream &Out, CFG &C, const char* nl,
Out << " : " << I.getData();
}
- Mgr.getConstraintManager().print(this, Out, nl, sep);
+ Mgr.getConstraintManager().print(this, Out, NL, Sep);
// Print checker-specific data.
- for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(),
- E = Mgr.Printers.end(); I != E; ++I) {
- (*I)->Print(Out, this, nl, sep);
- }
+ Mgr.getOwningEngine()->printState(Out, this, NL, Sep);
}
void ProgramState::printDOT(raw_ostream &Out, CFG &C) const {