1 //===-- LibStdcppUniquePointer.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "LibStdcpp.h"
11 
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/DataFormatters/FormattersHelpers.h"
14 #include "lldb/DataFormatters/TypeSynthetic.h"
15 #include "lldb/Utility/ConstString.h"
16 
17 #include <memory>
18 #include <vector>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 using namespace lldb_private::formatters;
23 
24 namespace {
25 
26 class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
27 public:
28   explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
29 
30   size_t CalculateNumChildren() override;
31 
32   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
33 
34   bool Update() override;
35 
36   bool MightHaveChildren() override;
37 
38   size_t GetIndexOfChildWithName(const ConstString &name) override;
39 
40   bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
41 
42 private:
43   ValueObjectSP m_ptr_obj;
44   ValueObjectSP m_obj_obj;
45   ValueObjectSP m_del_obj;
46 
47   ValueObjectSP GetTuple();
48 };
49 
50 } // end of anonymous namespace
51 
52 LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
53     lldb::ValueObjectSP valobj_sp)
54     : SyntheticChildrenFrontEnd(*valobj_sp) {
55   Update();
56 }
57 
58 ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
59   ValueObjectSP valobj_backend_sp = m_backend.GetSP();
60 
61   if (!valobj_backend_sp)
62     return nullptr;
63 
64   ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
65   if (!valobj_sp)
66     return nullptr;
67 
68   ValueObjectSP obj_child_sp =
69       valobj_sp->GetChildMemberWithName(ConstString("_M_t"), true);
70 
71   ValueObjectSP obj_subchild_sp =
72       obj_child_sp->GetChildMemberWithName(ConstString("_M_t"), true);
73 
74   // if there is a _M_t subchild, the tuple is found in
75   // the obj_subchild_sp (for libstdc++ 6.0.23).
76   if (obj_subchild_sp) {
77     return obj_subchild_sp;
78   }
79 
80   return obj_child_sp;
81 }
82 
83 bool LibStdcppUniquePtrSyntheticFrontEnd::Update() {
84   ValueObjectSP tuple_sp = GetTuple();
85 
86   if (!tuple_sp)
87     return false;
88 
89   std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
90       LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
91 
92   ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
93   if (ptr_obj)
94     m_ptr_obj = ptr_obj->Clone(ConstString("pointer"));
95 
96   ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
97   if (del_obj)
98     m_del_obj = del_obj->Clone(ConstString("deleter"));
99 
100   if (m_ptr_obj) {
101     Status error;
102     ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
103     if (error.Success()) {
104       m_obj_obj = obj_obj->Clone(ConstString("object"));
105     }
106   }
107 
108   return false;
109 }
110 
111 bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
112 
113 lldb::ValueObjectSP
114 LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
115   if (idx == 0)
116     return m_ptr_obj;
117   if (idx == 1)
118     return m_del_obj;
119   if (idx == 2)
120     return m_obj_obj;
121   return lldb::ValueObjectSP();
122 }
123 
124 size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
125   if (m_del_obj)
126     return 2;
127   return 1;
128 }
129 
130 size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
131     const ConstString &name) {
132   if (name == ConstString("ptr") || name == ConstString("pointer"))
133     return 0;
134   if (name == ConstString("del") || name == ConstString("deleter"))
135     return 1;
136   if (name == ConstString("obj") || name == ConstString("object") ||
137       name == ConstString("$$dereference$$"))
138     return 2;
139   return UINT32_MAX;
140 }
141 
142 bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
143     Stream &stream, const TypeSummaryOptions &options) {
144   if (!m_ptr_obj)
145     return false;
146 
147   bool success;
148   uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(0, &success);
149   if (!success)
150     return false;
151   if (ptr_value == 0)
152     stream.Printf("nullptr");
153   else
154     stream.Printf("0x%" PRIx64, ptr_value);
155   return true;
156 }
157 
158 SyntheticChildrenFrontEnd *
159 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
160     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
161   return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
162                     : nullptr);
163 }
164 
165 bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
166     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
167   LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
168   return formatter.GetSummary(stream, options);
169 }
170