Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -299,8 +299,9 @@ const CallEvent *Call) override; /// printState - Called by ProgramStateManager to print checker-specific data. - void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) override; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep, + const LocationContext *LCtx = nullptr) override; ProgramStateManager& getStateManager() override { return StateMgr; } Index: include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -155,7 +155,8 @@ /// printState - Called by ProgramStateManager to print checker-specific data. virtual void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) = 0; + const char *NL, const char *Sep, + const LocationContext *LCtx = nullptr) = 0; /// Called by CoreEngine when the analysis worklist is either empty or the // maximum number of analysis steps have been reached. Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -383,8 +383,62 @@ LCtx, Call); } +static void printInitializedTemporariesForContext(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep, + const LocationContext *LC) { + PrintingPolicy PP = + LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + for (auto I : State->get()) { + if (I.second != LC) + continue; + Out << '(' << I.second << ',' << I.first << ") "; + I.first->printPretty(Out, nullptr, PP); + Out << NL; + } +} + +static void printCXXNewAllocatorValuesForContext(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep, + const LocationContext *LC) { + PrintingPolicy PP = + LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + + for (auto I : State->get()) { + std::pair Key = I.first; + SVal Value = I.second; + if (Key.second != LC) + continue; + Out << '(' << Key.second << ',' << Key.first << ") "; + Key.first->printPretty(Out, nullptr, PP); + Out << " : " << Value << NL; + } +} + void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) { + const char *NL, const char *Sep, + const LocationContext *LCtx) { + if (LCtx) { + if (!State->get().isEmpty()) { + Out << Sep << "Initialized temporaries:" << NL; + + LCtx->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) { + printInitializedTemporariesForContext(Out, State, NL, Sep, LC); + }); + } + + if (!State->get().isEmpty()) { + Out << Sep << "operator new() allocator return values:" << NL; + + LCtx->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) { + printCXXNewAllocatorValuesForContext(Out, State, NL, Sep, LC); + }); + } + } + getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep); } Index: lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- lib/StaticAnalyzer/Core/ProgramState.cpp +++ lib/StaticAnalyzer/Core/ProgramState.cpp @@ -450,7 +450,7 @@ Mgr.getConstraintManager().print(this, Out, NL, Sep); // Print checker-specific data. - Mgr.getOwningEngine()->printState(Out, this, NL, Sep); + Mgr.getOwningEngine()->printState(Out, this, NL, Sep, LC); } void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LC) const {