From: Jordy Rose Date: Sun, 28 Aug 2011 19:11:56 +0000 (+0000) Subject: [analyzer] Introduce a new callback for checkers, printState, to be used for debug... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dbd658e139b3e0bf084f75feaea8d844af9e319f;p=clang [analyzer] Introduce a new callback for checkers, printState, to be used for debug-printing the contents of a ProgramState. Unlike the other callbacks, this one is a simple virtual method, since it is only to be used for debugging. This new callback replaces the old ProgramState::Printer interface, and allows us to move the printing of refcount bindings from CFRefCount to RetainReleaseChecker. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138728 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 ExplicitRegions, ArrayRef 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::Contains(ProgramStateTrait::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 > GDMContextsTy; GDMContextsTy GDMContexts; - /// Printers - A set of printer objects used for pretty-printing a ProgramState. - /// ProgramStateManager owns these objects. - std::vector Printers; - /// StateSet - FoldingSet containing all the states created for analyzing /// a particular function. This is used to unique states. llvm::FoldingSet 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& 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& 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 << ""; - Out << ":{"; - - // Get the contents of the pool. - if (const ARCounts *cnts = state->get(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(); - - 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(); - - 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; @@ -3622,6 +3569,62 @@ void RetainReleaseChecker::checkDeadSymbols(SymbolReaper &SymReaper, C.generateNode(state, Pred); } +//===----------------------------------------------------------------------===// +// 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 << ""; + Out << ":{"; + + // Get the contents of the pool. + if (const ARCounts *Cnts = State->get(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().isEmpty() || + state->get(SymbolRef()); +} + +void RetainReleaseChecker::printState(raw_ostream &Out, + const ProgramState *State, + const char *NL, const char *Sep) const { + + RefBindings B = State->get(); + + 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(); + + 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::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::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::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 {