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