Improve the libstdc++ smart pointer formatters

* Display the strong/weak count in the summary
* Display the pointed object as a synthetic member
* Create synthetic children for weak/strong count

Differential revision: https://reviews.llvm.org/D25726

llvm-svn: 284828
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSmartPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSmartPointer.cpp
new file mode 100644
index 0000000..4edeaab
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSmartPointer.cpp
@@ -0,0 +1,200 @@
+//===-- LibStdcppSmartPointer.cpp -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibStdcpp.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/Target.h"
+
+#include <memory>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace {
+
+class SharedPtrFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  explicit SharedPtrFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+  size_t CalculateNumChildren() override;
+
+  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+  bool Update() override;
+
+  bool MightHaveChildren() override;
+
+  size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+  bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
+
+private:
+  ValueObjectSP m_ptr_obj;
+  ValueObjectSP m_obj_obj;
+  ValueObjectSP m_use_obj;
+  ValueObjectSP m_weak_obj;
+
+  uint8_t m_ptr_size = 0;
+  lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid;
+
+  bool IsEmpty();
+  bool IsValid();
+};
+
+} // end of anonymous namespace
+
+SharedPtrFrontEnd::SharedPtrFrontEnd(lldb::ValueObjectSP valobj_sp)
+    : SyntheticChildrenFrontEnd(*valobj_sp) {
+  Update();
+}
+
+bool SharedPtrFrontEnd::Update() {
+  ValueObjectSP valobj_backend_sp = m_backend.GetSP();
+  if (!valobj_backend_sp)
+    return false;
+
+  ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
+  if (!valobj_sp)
+    return false;
+
+  TargetSP target_sp(valobj_sp->GetTargetSP());
+  if (!target_sp)
+    return false;
+
+  m_byte_order = target_sp->GetArchitecture().GetByteOrder();
+  m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
+
+  m_ptr_obj = valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true);
+
+  m_use_obj = valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"),
+                                             ConstString("_M_pi"),
+                                             ConstString("_M_use_count")});
+
+  m_weak_obj = valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"),
+                                              ConstString("_M_pi"),
+                                              ConstString("_M_weak_count")});
+
+  // libstdc++ implements the weak usage count in a way that it is offset by 1
+  // if the strong count is not 0 (as part of a preformance optimization). We
+  // want to undo this before showing the weak count to the user as an offseted
+  // weak count would be very confusing.
+  if (m_use_obj && m_weak_obj && m_use_obj->GetValueAsUnsigned(0) > 0) {
+    bool success = false;
+    uint64_t count = m_weak_obj->GetValueAsUnsigned(0, &success) - 1;
+    if (success) {
+      auto data = std::make_shared<DataBufferHeap>(&count, sizeof(count));
+      m_weak_obj = CreateValueObjectFromData(
+          "weak_count", DataExtractor(data, m_byte_order, m_ptr_size),
+          m_weak_obj->GetExecutionContextRef(), m_weak_obj->GetCompilerType());
+    }
+  }
+
+  if (m_ptr_obj && !IsEmpty()) {
+    Error error;
+    m_obj_obj = m_ptr_obj->Dereference(error);
+    if (error.Success()) {
+      m_obj_obj->SetName(ConstString("object"));
+    }
+  }
+
+  return false;
+}
+
+bool SharedPtrFrontEnd::MightHaveChildren() { return true; }
+
+lldb::ValueObjectSP SharedPtrFrontEnd::GetChildAtIndex(size_t idx) {
+  if (idx == 0)
+    return m_obj_obj;
+  if (idx == 1)
+    return m_ptr_obj;
+  if (idx == 2)
+    return m_use_obj;
+  if (idx == 3)
+    return m_weak_obj;
+  return lldb::ValueObjectSP();
+}
+
+size_t SharedPtrFrontEnd::CalculateNumChildren() {
+  if (IsEmpty())
+    return 0;
+  return 1;
+}
+
+size_t SharedPtrFrontEnd::GetIndexOfChildWithName(const ConstString &name) {
+  if (name == ConstString("obj") || name == ConstString("object"))
+    return 0;
+  if (name == ConstString("ptr") || name == ConstString("pointer") ||
+      name == ConstString("_M_ptr"))
+    return 1;
+  if (name == ConstString("cnt") || name == ConstString("count") ||
+      name == ConstString("use_count") || name == ConstString("strong") ||
+      name == ConstString("_M_use_count"))
+    return 2;
+  if (name == ConstString("weak") || name == ConstString("weak_count") ||
+      name == ConstString("_M_weak_count"))
+    return 3;
+  return UINT32_MAX;
+}
+
+bool SharedPtrFrontEnd::GetSummary(Stream &stream,
+                                   const TypeSummaryOptions &options) {
+  if (!IsValid())
+    return false;
+
+  if (IsEmpty()) {
+    stream.Printf("nullptr");
+  } else {
+    Error error;
+    bool print_pointee = false;
+    if (m_obj_obj) {
+      if (m_obj_obj->DumpPrintableRepresentation(
+              stream, ValueObject::eValueObjectRepresentationStyleSummary,
+              lldb::eFormatInvalid,
+              ValueObject::ePrintableRepresentationSpecialCasesDisable,
+              false)) {
+        print_pointee = true;
+      }
+    }
+    if (!print_pointee)
+      stream.Printf("ptr = 0x%" PRIx64, m_ptr_obj->GetValueAsUnsigned(0));
+  }
+
+  if (m_use_obj && m_use_obj->GetError().Success())
+    stream.Printf(" strong=%" PRIu64, m_use_obj->GetValueAsUnsigned(0));
+
+  if (m_weak_obj && m_weak_obj->GetError().Success())
+    stream.Printf(" weak=%" PRIu64, m_weak_obj->GetValueAsUnsigned(0));
+
+  return true;
+}
+
+bool SharedPtrFrontEnd::IsValid() { return m_ptr_obj != nullptr; }
+
+bool SharedPtrFrontEnd::IsEmpty() {
+  return !IsValid() || m_ptr_obj->GetValueAsUnsigned(0) == 0 ||
+         (m_use_obj && m_use_obj->GetValueAsUnsigned(0) == 0);
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
+    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+  return valobj_sp ? new SharedPtrFrontEnd(valobj_sp) : nullptr;
+}
+
+bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+  SharedPtrFrontEnd formatter(valobj.GetSP());
+  return formatter.GetSummary(stream, options);
+}