]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Plugins / Language / CPlusPlus / LibCxxVariant.cpp
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"
10 #include "lldb/DataFormatters/FormattersHelpers.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
68 LibcxxVariantIndexValidity
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 {
118 bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
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 {
177     return formatters::ExtractIndexFromString(name.GetCString());
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
249 SyntheticChildrenFrontEnd *
250 formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
251                                          lldb::ValueObjectSP valobj_sp) {
252   if (valobj_sp)
253     return new VariantFrontEnd(*valobj_sp);
254   return nullptr;
255 }