LLDB  mainline
LibCxxVariant.cpp
Go to the documentation of this file.
1 //===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===//
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 "LibCxxVariant.h"
11 
12 #include "llvm/ADT/Optional.h"
13 #include "llvm/ADT/ScopeExit.h"
14 
15 using namespace lldb;
16 using namespace lldb_private;
17 
18 // libc++ variant implementation contains two members that we care about both
19 // are contained in the __impl member.
20 // - __index which tells us which of the variadic template types is the active
21 // type for the variant
22 // - __data is a variadic union which recursively contains itself as member
23 // which refers to the tailing variadic types.
24 // - __head which refers to the leading non pack type
25 // - __value refers to the actual value contained
26 // - __tail which refers to the remaining pack types
27 //
28 // e.g. given std::variant<int,double,char> v1
29 //
30 // (lldb) frame var -R v1.__impl.__data
31 //(... __union<... 0, int, double, char>) v1.__impl.__data = {
32 // ...
33 // __head = {
34 // __value = ...
35 // }
36 // __tail = {
37 // ...
38 // __head = {
39 // __value = ...
40 // }
41 // __tail = {
42 // ...
43 // __head = {
44 // __value = ...
45 // ...
46 //
47 // So given
48 // - __index equal to 0 the active value is contained in
49 //
50 // __data.__head.__value
51 //
52 // - __index equal to 1 the active value is contained in
53 //
54 // __data.__tail.__head.__value
55 //
56 // - __index equal to 2 the active value is contained in
57 //
58 // __data.__tail.__tail.__head.__value
59 //
60 
61 namespace {
62 // libc++ std::variant index could have one of three states
63 // 1) VALID, we can obtain it and its not variant_npos
64 // 2) INVALID, we can't obtain it or it is not a type we expect
65 // 3) NPOS, its value is variant_npos which means the variant has no value
66 enum class LibcxxVariantIndexValidity { VALID, INVALID, NPOS };
67 
69 LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
70  ValueObjectSP index_sp(
71  impl_sp->GetChildMemberWithName(ConstString("__index"), true));
72 
73  if (!index_sp)
74  return LibcxxVariantIndexValidity::INVALID;
75 
76  int64_t index_value = index_sp->GetValueAsSigned(0);
77 
78  if (index_value == -1)
79  return LibcxxVariantIndexValidity::NPOS;
80 
81  return LibcxxVariantIndexValidity::VALID;
82 }
83 
84 llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
85  ValueObjectSP index_sp(
86  impl_sp->GetChildMemberWithName(ConstString("__index"), true));
87 
88  if (!index_sp)
89  return {};
90 
91  return {index_sp->GetValueAsUnsigned(0)};
92 }
93 
94 ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
95  ValueObjectSP data_sp(
96  impl_sp->GetChildMemberWithName(ConstString("__data"), true));
97 
98  if (!data_sp)
99  return ValueObjectSP{};
100 
101  ValueObjectSP current_level = data_sp;
102  for (uint64_t n = index; n != 0; --n) {
103  ValueObjectSP tail_sp(
104  current_level->GetChildMemberWithName(ConstString("__tail"), true));
105 
106  if (!tail_sp)
107  return ValueObjectSP{};
108 
109  current_level = tail_sp;
110  }
111 
112  return current_level->GetChildMemberWithName(ConstString("__head"), true);
113 }
114 } // namespace
115 
116 namespace lldb_private {
117 namespace formatters {
119  const TypeSummaryOptions &options) {
120  ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
121  if (!valobj_sp)
122  return false;
123 
124  ValueObjectSP impl_sp(
125  valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
126 
127  if (!impl_sp)
128  return false;
129 
130  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
131 
132  if (validity == LibcxxVariantIndexValidity::INVALID)
133  return false;
134 
135  if (validity == LibcxxVariantIndexValidity::NPOS) {
136  stream.Printf(" No Value");
137  return true;
138  }
139 
140  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
141 
142  if (!optional_index_value)
143  return false;
144 
145  uint64_t index_value = *optional_index_value;
146 
147  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
148 
149  if (!nth_head)
150  return false;
151 
152  CompilerType head_type = nth_head->GetCompilerType();
153 
154  if (!head_type)
155  return false;
156 
157  CompilerType template_type = head_type.GetTypeTemplateArgument(1);
158 
159  if (!template_type)
160  return false;
161 
162  stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString());
163 
164  return true;
165 }
166 } // namespace formatters
167 } // namespace lldb_private
168 
169 namespace {
170 class VariantFrontEnd : public SyntheticChildrenFrontEnd {
171 public:
172  VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
173  Update();
174  }
175 
176  size_t GetIndexOfChildWithName(ConstString name) override {
178  }
179 
180  bool MightHaveChildren() override { return true; }
181  bool Update() override;
182  size_t CalculateNumChildren() override { return m_size; }
183  ValueObjectSP GetChildAtIndex(size_t idx) override;
184 
185 private:
186  size_t m_size = 0;
187  ValueObjectSP m_base_sp;
188 };
189 } // namespace
190 
191 bool VariantFrontEnd::Update() {
192  m_size = 0;
193  ValueObjectSP impl_sp(
194  m_backend.GetChildMemberWithName(ConstString("__impl"), true));
195  if (!impl_sp)
196  return false;
197 
198  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
199 
200  if (validity == LibcxxVariantIndexValidity::INVALID)
201  return false;
202 
203  if (validity == LibcxxVariantIndexValidity::NPOS)
204  return true;
205 
206  m_size = 1;
207 
208  return false;
209 }
210 
211 ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
212  if (idx >= m_size)
213  return ValueObjectSP();
214 
215  ValueObjectSP impl_sp(
216  m_backend.GetChildMemberWithName(ConstString("__impl"), true));
217 
218  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
219 
220  if (!optional_index_value)
221  return ValueObjectSP();
222 
223  uint64_t index_value = *optional_index_value;
224 
225  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
226 
227  if (!nth_head)
228  return ValueObjectSP();
229 
230  CompilerType head_type = nth_head->GetCompilerType();
231 
232  if (!head_type)
233  return ValueObjectSP();
234 
235  CompilerType template_type = head_type.GetTypeTemplateArgument(1);
236 
237  if (!template_type)
238  return ValueObjectSP();
239 
240  ValueObjectSP head_value(
241  nth_head->GetChildMemberWithName(ConstString("__value"), true));
242 
243  if (!head_value)
244  return ValueObjectSP();
245 
246  return head_value->Clone(ConstString(ConstString("Value").AsCString()));
247 }
248 
251  lldb::ValueObjectSP valobj_sp) {
252  if (valobj_sp)
253  return new VariantFrontEnd(*valobj_sp);
254  return nullptr;
255 }
bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t ExtractIndexFromString(const char *item_name)
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Definition: VectorType.cpp:168
A uniqued constant string class.
Definition: ConstString.h:38
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
Definition: SBAddress.h:15
CompilerType GetTypeTemplateArgument(size_t idx) const
LibcxxVariantIndexValidity
SyntheticChildrenFrontEnd * LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
ConstString GetTypeName() const
virtual lldb::ValueObjectSP GetNonSyntheticValue()