1 //===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "LibCxxVariant.h"
11 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/ScopeExit.h"
17 using namespace lldb_private;
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
29 // e.g. given std::variant<int,double,char> v1
31 // (lldb) frame var -R v1.__impl.__data
32 //(... __union<... 0, int, double, char>) v1.__impl.__data = {
49 // - __index equal to 0 the active value is contained in
51 // __data.__head.__value
53 // - __index equal to 1 the active value is contained in
55 // __data.__tail.__head.__value
57 // - __index equal to 2 the active value is contained in
59 // __data.__tail.__tail.__head.__value
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 };
69 LibcxxVariantIndexValidity
70 LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
71 ValueObjectSP index_sp(
72 impl_sp->GetChildMemberWithName(ConstString("__index"), true));
75 return LibcxxVariantIndexValidity::INVALID;
77 int64_t index_value = index_sp->GetValueAsSigned(0);
79 if (index_value == -1)
80 return LibcxxVariantIndexValidity::NPOS;
82 return LibcxxVariantIndexValidity::VALID;
85 llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
86 ValueObjectSP index_sp(
87 impl_sp->GetChildMemberWithName(ConstString("__index"), true));
92 return {index_sp->GetValueAsUnsigned(0)};
95 ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
96 ValueObjectSP data_sp(
97 impl_sp->GetChildMemberWithName(ConstString("__data"), true));
100 return ValueObjectSP{};
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));
108 return ValueObjectSP{};
110 current_level = tail_sp;
113 return current_level->GetChildMemberWithName(ConstString("__head"), true);
117 namespace lldb_private {
118 namespace formatters {
119 bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
120 const TypeSummaryOptions &options) {
121 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
125 ValueObjectSP impl_sp(
126 valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
131 LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
133 if (validity == LibcxxVariantIndexValidity::INVALID)
136 if (validity == LibcxxVariantIndexValidity::NPOS) {
137 stream.Printf(" No Value");
141 auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
143 if (!optional_index_value)
146 uint64_t index_value = *optional_index_value;
148 ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
153 CompilerType head_type = nth_head->GetCompilerType();
158 CompilerType template_type = head_type.GetTypeTemplateArgument(1);
163 stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString());
167 } // namespace formatters
168 } // namespace lldb_private
171 class VariantFrontEnd : public SyntheticChildrenFrontEnd {
173 VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
177 size_t GetIndexOfChildWithName(const ConstString &name) override {
178 return formatters::ExtractIndexFromString(name.GetCString());
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;
188 ValueObjectSP m_base_sp;
192 bool VariantFrontEnd::Update() {
194 ValueObjectSP impl_sp(
195 m_backend.GetChildMemberWithName(ConstString("__impl"), true));
199 LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
201 if (validity == LibcxxVariantIndexValidity::INVALID)
204 if (validity == LibcxxVariantIndexValidity::NPOS)
212 ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
214 return ValueObjectSP();
216 ValueObjectSP impl_sp(
217 m_backend.GetChildMemberWithName(ConstString("__impl"), true));
219 auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
221 if (!optional_index_value)
222 return ValueObjectSP();
224 uint64_t index_value = *optional_index_value;
226 ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
229 return ValueObjectSP();
231 CompilerType head_type = nth_head->GetCompilerType();
234 return ValueObjectSP();
236 CompilerType template_type = head_type.GetTypeTemplateArgument(1);
239 return ValueObjectSP();
241 ValueObjectSP head_value(
242 nth_head->GetChildMemberWithName(ConstString("__value"), true));
245 return ValueObjectSP();
247 return head_value->Clone(ConstString(ConstString("Value").AsCString()));
250 SyntheticChildrenFrontEnd *
251 formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
252 lldb::ValueObjectSP valobj_sp) {
254 return new VariantFrontEnd(*valobj_sp);