#include "LibStdcpp.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/ValueObject/ValueObject.h"
#include <memory>
#include <vector>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
namespace {
class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
llvm::Expected<uint32_t> CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
lldb::ChildCacheState Update() override;
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
private:
ValueObject *m_ptr_obj = nullptr;
ValueObject* m_del_obj = nullptr;
ValueObjectSP GetTuple();
};
}
LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {
Update();
}
ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
ValueObjectSP valobj_backend_sp = m_backend.GetSP();
if (!valobj_backend_sp)
return nullptr;
ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
if (!valobj_sp)
return nullptr;
ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName("_M_t");
if (!obj_child_sp)
return nullptr;
ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName("_M_t");
if (obj_subchild_sp) {
return obj_subchild_sp;
}
return obj_child_sp;
}
lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
ValueObjectSP tuple_sp = GetTuple();
if (!tuple_sp)
return lldb::ChildCacheState::eRefetch;
std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
if (ptr_obj)
m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();
if (llvm::expectedToOptional(tuple_sp->GetByteSize()).value_or(0) >
llvm::expectedToOptional(ptr_obj->GetByteSize()).value_or(0)) {
ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
if (del_obj)
m_del_obj = del_obj->Clone(ConstString("deleter")).get();
}
return lldb::ChildCacheState::eRefetch;
}
lldb::ValueObjectSP
LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
if (idx == 0 && m_ptr_obj)
return m_ptr_obj->GetSP();
if (idx == 1 && m_del_obj)
return m_del_obj->GetSP();
if (idx == 2) {
if (m_ptr_obj) {
Status status;
auto value_sp = m_ptr_obj->Dereference(status);
if (status.Success()) {
return value_sp;
}
}
}
return lldb::ValueObjectSP();
}
llvm::Expected<uint32_t>
LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
if (m_del_obj)
return 2;
return 1;
}
llvm::Expected<size_t>
LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
if (name == "ptr" || name == "pointer")
return 0;
if (name == "del" || name == "deleter")
return 1;
if (name == "obj" || name == "object" || name == "$$dereference$$")
return 2;
return llvm::createStringError("Type has no child named '%s'",
name.AsCString());
}
bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
Stream &stream, const TypeSummaryOptions &options) {
if (!m_ptr_obj)
return false;
DumpCxxSmartPtrPointerSummary(stream, *m_ptr_obj, options);
return true;
}
SyntheticChildrenFrontEnd *
lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
: nullptr);
}
bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
return formatter.GetSummary(stream, options);
}