Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -253,7 +253,12 @@ virtual bool scanReachableSymbols(Store S, const MemRegion *R, ScanReachableSymbols &Visitor) = 0; - virtual void print(Store store, raw_ostream &Out, const char* nl) = 0; + virtual void print(raw_ostream &Out, Store S, const char *NL, + const char *Sep) const = 0; + + virtual void printDiff(raw_ostream &Out, Store CurrentStore, + Store PreviousStore, const char *NL, + const char *Sep) const = 0; class BindingsHandler { public: Index: clang/lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -446,7 +446,7 @@ const ASTContext &Ctx = Mgr.getContext(); // Print out the store. - Mgr.getStoreManager().print(getStore(), Out, NL); + Mgr.getStoreManager().print(Out, getStore(), NL, Sep); // Print out the environment. Env.print(Out, NL, Sep, Ctx, LCtx); @@ -482,9 +482,10 @@ ProgramStateManager &Mgr = getStateManager(); const ASTContext &Ctx = Mgr.getContext(); + const Store PreviousStore = PreviousState->getStore(); // Print out the store. - Mgr.getStoreManager().print(getStore(), Out, NL); + Mgr.getStoreManager().printDiff(Out, getStore(), PreviousStore, NL, Sep); // Print out the environment. Env.print(Out, NL, Sep, Ctx, CurrentLCtx); Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -206,18 +206,51 @@ return asImmutableMap().getRootWithoutRetain(); } - void dump(raw_ostream &OS, const char *nl) const { - for (iterator I = begin(), E = end(); I != E; ++I) { - const ClusterBindings &Cluster = I.getData(); - for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end(); - CI != CE; ++CI) { - OS << ' ' << CI.getKey() << " : " << CI.getData() << nl; - } - OS << nl; - } - } - - LLVM_DUMP_METHOD void dump() const { dump(llvm::errs(), "\n"); } + void print(raw_ostream &Out, const char *NL = "\n") const { + for (iterator I = begin(), E = end(); I != E; ++I) { + const ClusterBindings &Cluster = I.getData(); + for (ClusterBindings::iterator CI = Cluster.begin(); CI != Cluster.end(); + ++CI) { + Out << ' ' << CI.getKey() << " : " << CI.getData() << NL; + } + Out << NL; + } + } + + void printDiff(raw_ostream &Out, RegionBindingsRef PreviousCluster, + const char *NL = "\n") const { + // If there is no previous cluster just print the current cluster. + if (PreviousCluster.isEmpty()) { + print(Out, NL); + return; + } + + bool IsDifferent = false; + for (iterator I = begin(); I != end(); ++I) { + // Skip duplications. + if (std::find(PreviousCluster.begin(), PreviousCluster.end(), *I) != + PreviousCluster.end()) + continue; + + // In the beginning add a little space. + if (!IsDifferent) { + Out << NL << NL; + IsDifferent = true; + } + + const ClusterBindings &Cluster = I.getData(); + for (ClusterBindings::iterator CI = Cluster.begin(); CI != Cluster.end(); + ++CI) { + Out << ' ' << CI.getKey() << " : " << CI.getData() << NL; + } + Out << NL; + } + + if (!IsDifferent) + Out << " No difference." << NL; + } + + LLVM_DUMP_METHOD void dump() const { print(llvm::errs(), "\n"); } }; } // end anonymous namespace @@ -594,7 +627,11 @@ RBFactory.getTreeFactory()); } - void print(Store store, raw_ostream &Out, const char* nl) override; + void print(raw_ostream &Out, Store S, const char *NL = "\n", + const char *Sep = "") const override; + + void printDiff(raw_ostream &Out, Store CurrentStore, Store PreviousStore, + const char *NL = "\n", const char *Sep = "") const override; void iterBindings(Store store, BindingsHandler& f) override { RegionBindingsRef B = getRegionBindings(store); @@ -2611,11 +2648,31 @@ // Utility methods. //===----------------------------------------------------------------------===// -void RegionStoreManager::print(Store store, raw_ostream &OS, - const char* nl) { - RegionBindingsRef B = getRegionBindings(store); - OS << "Store (direct and default bindings), " - << B.asStore() - << " :" << nl; - B.dump(OS, nl); +void RegionStoreManager::print(raw_ostream &Out, Store S, const char *NL, + const char *Sep) const { + RegionBindingsRef Bindings = getRegionBindings(S); + + Out << Sep; + if (Bindings.isEmpty()) { + Out << "Store is empty." << NL; + return; + } + + Out << "Store <" << Bindings.asStore() << ">:"; + Bindings.print(Out, NL); +} + +void RegionStoreManager::printDiff(raw_ostream &Out, Store CurrentStore, + Store PreviousStore, const char *NL, + const char *Sep) const { + RegionBindingsRef Bindings = getRegionBindings(CurrentStore); + + Out << Sep; + if (Bindings.isEmpty()) { + Out << "Store is empty." << NL; + return; + } + + Out << "Store <" << Bindings.asStore() << ">:"; + Bindings.printDiff(Out, getRegionBindings(PreviousStore), NL); }