@@ -67,8 +67,8 @@ class BindingKey {
6767 isa<ObjCIvarRegion, CXXDerivedObjectRegion>(r)) &&
6868 " Not a base" );
6969 }
70- public:
7170
71+ public:
7272 bool isDirect () const { return P.getInt () & Direct; }
7373 bool hasSymbolicOffset () const { return P.getInt () & Symbolic; }
7474
@@ -232,27 +232,75 @@ class RegionBindingsRef : public llvm::ImmutableMapRef<const MemRegion *,
232232
233233 void printJson (raw_ostream &Out, const char *NL = " \n " ,
234234 unsigned int Space = 0 , bool IsDot = false ) const {
235- for (iterator I = begin (), E = end (); I != E; ++I) {
236- // TODO: We might need a .printJson for I.getKey() as well.
235+ using namespace llvm ;
236+ DenseMap<const MemRegion *, std::string> StringifyCache;
237+ auto ToString = [&StringifyCache](const MemRegion *R) {
238+ auto [Place, Inserted] = StringifyCache.try_emplace (R);
239+ if (!Inserted)
240+ return Place->second ;
241+ std::string Res;
242+ raw_string_ostream OS (Res);
243+ OS << R;
244+ Place->second = Res;
245+ return Res;
246+ };
247+
248+ using Cluster =
249+ std::pair<const MemRegion *, ImmutableMap<BindingKey, SVal>>;
250+ using Binding = std::pair<BindingKey, SVal>;
251+
252+ const auto ClusterSortKey = [&ToString](const Cluster *C) {
253+ const MemRegion *Key = C->first ;
254+ return std::tuple{isa<MemSpaceRegion>(Key), ToString (Key)};
255+ };
256+
257+ const auto MemSpaceBeforeRegionName = [&ClusterSortKey](const Cluster *L,
258+ const Cluster *R) {
259+ return ClusterSortKey (L) < ClusterSortKey (R);
260+ };
261+
262+ const auto BindingSortKey = [&ToString](const Binding *BPtr) {
263+ const BindingKey &Key = BPtr->first ;
264+ return std::tuple{Key.isDirect (), !Key.hasSymbolicOffset (),
265+ ToString (Key.getRegion ()), Key.getOffset ()};
266+ };
267+
268+ const auto DefaultBindingBeforeDirectBindings =
269+ [&BindingSortKey](const Binding *LPtr, const Binding *RPtr) {
270+ return BindingSortKey (LPtr) < BindingSortKey (RPtr);
271+ };
272+
273+ const auto AddrOf = [](const auto &Item) { return &Item; };
274+
275+ std::vector<const Cluster *> SortedClusters;
276+ SortedClusters.reserve (std::distance (begin (), end ()));
277+ append_range (SortedClusters, map_range (*this , AddrOf));
278+ llvm::sort (SortedClusters, MemSpaceBeforeRegionName);
279+
280+ for (auto [Idx, C] : llvm::enumerate (SortedClusters)) {
281+ const auto &[BaseRegion, Bindings] = *C;
237282 Indent (Out, Space, IsDot)
238- << " { \" cluster\" : \" " << I.getKey () << " \" , \" pointer\" : \" "
239- << (const void *)I.getKey () << " \" , \" items\" : [" << NL;
283+ << " { \" cluster\" : \" " << BaseRegion << " \" , \" pointer\" : \" "
284+ << (const void *)BaseRegion << " \" , \" items\" : [" << NL;
285+
286+ std::vector<const Binding *> SortedBindings;
287+ SortedBindings.reserve (std::distance (Bindings.begin (), Bindings.end ()));
288+ append_range (SortedBindings, map_range (Bindings, AddrOf));
289+ llvm::sort (SortedBindings, DefaultBindingBeforeDirectBindings);
240290
241291 ++Space;
242- const ClusterBindings &CB = I.getData ();
243- for (ClusterBindings::iterator CI = CB.begin (), CE = CB.end (); CI != CE;
244- ++CI) {
245- Indent (Out, Space, IsDot) << " { " << CI.getKey () << " , \" value\" : " ;
246- CI.getData ().printJson (Out, /* AddQuotes=*/ true );
292+ for (auto [Idx, B] : llvm::enumerate (SortedBindings)) {
293+ const auto &[Key, Value] = *B;
294+ Indent (Out, Space, IsDot) << " { " << Key << " , \" value\" : " ;
295+ Value.printJson (Out, /* AddQuotes=*/ true );
247296 Out << " }" ;
248- if (std::next (CI) != CE )
297+ if (Idx != SortedBindings. size () - 1 )
249298 Out << ' ,' ;
250299 Out << NL;
251300 }
252-
253301 --Space;
254302 Indent (Out, Space, IsDot) << " ]}" ;
255- if (std::next (I) != E )
303+ if (Idx != SortedClusters. size () - 1 )
256304 Out << ' ,' ;
257305 Out << NL;
258306 }
0 commit comments