1//===-- LibStdcppUniquePointer.cpp ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "LibStdcpp.h"
10
11#include "lldb/DataFormatters/FormattersHelpers.h"
12#include "lldb/DataFormatters/TypeSynthetic.h"
13#include "lldb/Utility/ConstString.h"
14#include "lldb/ValueObject/ValueObject.h"
15
16#include <memory>
17#include <vector>
18
19using namespace lldb;
20using namespace lldb_private;
21using namespace lldb_private::formatters;
22
23namespace {
24
25class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
26public:
27 explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
28
29 llvm::Expected<uint32_t> CalculateNumChildren() override;
30
31 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
32
33 lldb::ChildCacheState Update() override;
34
35 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
36
37 bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
38
39private:
40 // The lifetime of a ValueObject and all its derivative ValueObjects
41 // (children, clones, etc.) is managed by a ClusterManager. These
42 // objects are only destroyed when every shared pointer to any of them
43 // is destroyed, so we must not store a shared pointer to any ValueObject
44 // derived from our backend ValueObject (since we're in the same cluster).
45 ValueObject* m_ptr_obj = nullptr;
46 ValueObject* m_obj_obj = nullptr;
47 ValueObject* m_del_obj = nullptr;
48
49 ValueObjectSP GetTuple();
50};
51
52} // end of anonymous namespace
53
54LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
55 lldb::ValueObjectSP valobj_sp)
56 : SyntheticChildrenFrontEnd(*valobj_sp) {
57 Update();
58}
59
60ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
61 ValueObjectSP valobj_backend_sp = m_backend.GetSP();
62
63 if (!valobj_backend_sp)
64 return nullptr;
65
66 ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
67 if (!valobj_sp)
68 return nullptr;
69
70 ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName(name: "_M_t");
71 if (!obj_child_sp)
72 return nullptr;
73
74 ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName(name: "_M_t");
75
76 // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp
77 // (for libstdc++ 6.0.23).
78 if (obj_subchild_sp) {
79 return obj_subchild_sp;
80 }
81
82 return obj_child_sp;
83}
84
85lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
86 ValueObjectSP tuple_sp = GetTuple();
87
88 if (!tuple_sp)
89 return lldb::ChildCacheState::eRefetch;
90
91 std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
92 LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
93
94 ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(idx: 0);
95 if (ptr_obj)
96 m_ptr_obj = ptr_obj->Clone(new_name: ConstString("pointer")).get();
97
98 // Add a 'deleter' child if there was a non-empty deleter type specified.
99 //
100 // The object might have size=1 in the TypeSystem but occupies no dedicated
101 // storage due to no_unique_address, so infer the actual size from the total
102 // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then
103 // the deleter is empty and should be hidden.
104 if (llvm::expectedToOptional(E: tuple_sp->GetByteSize()).value_or(u: 0) >
105 llvm::expectedToOptional(E: ptr_obj->GetByteSize()).value_or(u: 0)) {
106 ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(idx: 1);
107 if (del_obj)
108 m_del_obj = del_obj->Clone(new_name: ConstString("deleter")).get();
109 }
110 m_obj_obj = nullptr;
111
112 return lldb::ChildCacheState::eRefetch;
113}
114
115lldb::ValueObjectSP
116LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
117 if (idx == 0 && m_ptr_obj)
118 return m_ptr_obj->GetSP();
119 if (idx == 1 && m_del_obj)
120 return m_del_obj->GetSP();
121 if (idx == 2) {
122 if (m_ptr_obj && !m_obj_obj) {
123 Status error;
124 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
125 if (error.Success()) {
126 m_obj_obj = obj_obj->Clone(new_name: ConstString("object")).get();
127 }
128 }
129 if (m_obj_obj)
130 return m_obj_obj->GetSP();
131 }
132 return lldb::ValueObjectSP();
133}
134
135llvm::Expected<uint32_t>
136LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
137 if (m_del_obj)
138 return 2;
139 return 1;
140}
141
142llvm::Expected<size_t>
143LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
144 if (name == "ptr" || name == "pointer")
145 return 0;
146 if (name == "del" || name == "deleter")
147 return 1;
148 if (name == "obj" || name == "object" || name == "$$dereference$$")
149 return 2;
150 return llvm::createStringError(Fmt: "Type has no child named '%s'",
151 Vals: name.AsCString());
152}
153
154bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
155 Stream &stream, const TypeSummaryOptions &options) {
156 if (!m_ptr_obj)
157 return false;
158
159 bool success;
160 uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(fail_value: 0, success: &success);
161 if (!success)
162 return false;
163 if (ptr_value == 0)
164 stream.Printf(format: "nullptr");
165 else
166 stream.Printf(format: "0x%" PRIx64, ptr_value);
167 return true;
168}
169
170SyntheticChildrenFrontEnd *
171lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
172 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
173 return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
174 : nullptr);
175}
176
177bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
178 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
179 LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
180 return formatter.GetSummary(stream, options);
181}
182

source code of lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp