diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 674099dd7e1f0..085f0ef9a5fb9 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -67,8 +67,8 @@ class BindingKey { isa(r)) && "Not a base"); } -public: +public: bool isDirect() const { return P.getInt() & Direct; } bool hasSymbolicOffset() const { return P.getInt() & Symbolic; } @@ -232,27 +232,75 @@ class RegionBindingsRef : public llvm::ImmutableMapRef StringifyCache; + auto ToString = [&StringifyCache](const MemRegion *R) { + auto [Place, Inserted] = StringifyCache.try_emplace(R); + if (!Inserted) + return Place->second; + std::string Res; + raw_string_ostream OS(Res); + OS << R; + Place->second = Res; + return Res; + }; + + using Cluster = + std::pair>; + using Binding = std::pair; + + const auto ClusterSortKey = [&ToString](const Cluster *C) { + const MemRegion *Key = C->first; + return std::tuple{isa(Key), ToString(Key)}; + }; + + const auto MemSpaceBeforeRegionName = [&ClusterSortKey](const Cluster *L, + const Cluster *R) { + return ClusterSortKey(L) < ClusterSortKey(R); + }; + + const auto BindingSortKey = [&ToString](const Binding *BPtr) { + const BindingKey &Key = BPtr->first; + return std::tuple{Key.isDirect(), !Key.hasSymbolicOffset(), + ToString(Key.getRegion()), Key.getOffset()}; + }; + + const auto DefaultBindingBeforeDirectBindings = + [&BindingSortKey](const Binding *LPtr, const Binding *RPtr) { + return BindingSortKey(LPtr) < BindingSortKey(RPtr); + }; + + const auto AddrOf = [](const auto &Item) { return &Item; }; + + std::vector SortedClusters; + SortedClusters.reserve(std::distance(begin(), end())); + append_range(SortedClusters, map_range(*this, AddrOf)); + llvm::sort(SortedClusters, MemSpaceBeforeRegionName); + + for (auto [Idx, C] : llvm::enumerate(SortedClusters)) { + const auto &[BaseRegion, Bindings] = *C; Indent(Out, Space, IsDot) - << "{ \"cluster\": \"" << I.getKey() << "\", \"pointer\": \"" - << (const void *)I.getKey() << "\", \"items\": [" << NL; + << "{ \"cluster\": \"" << BaseRegion << "\", \"pointer\": \"" + << (const void *)BaseRegion << "\", \"items\": [" << NL; + + std::vector SortedBindings; + SortedBindings.reserve(std::distance(Bindings.begin(), Bindings.end())); + append_range(SortedBindings, map_range(Bindings, AddrOf)); + llvm::sort(SortedBindings, DefaultBindingBeforeDirectBindings); ++Space; - const ClusterBindings &CB = I.getData(); - for (ClusterBindings::iterator CI = CB.begin(), CE = CB.end(); CI != CE; - ++CI) { - Indent(Out, Space, IsDot) << "{ " << CI.getKey() << ", \"value\": "; - CI.getData().printJson(Out, /*AddQuotes=*/true); + for (auto [Idx, B] : llvm::enumerate(SortedBindings)) { + const auto &[Key, Value] = *B; + Indent(Out, Space, IsDot) << "{ " << Key << ", \"value\": "; + Value.printJson(Out, /*AddQuotes=*/true); Out << " }"; - if (std::next(CI) != CE) + if (Idx != SortedBindings.size() - 1) Out << ','; Out << NL; } - --Space; Indent(Out, Space, IsDot) << "]}"; - if (std::next(I) != E) + if (Idx != SortedClusters.size() - 1) Out << ','; Out << NL; }