LLDB mainline
MsvcStlVariant.cpp
Go to the documentation of this file.
1//===-- MsvcStlVariant.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 "MsvcStl.h"
12#include <optional>
13
14using namespace lldb;
15using namespace lldb_private;
16
17namespace {
18
19// A variant when using DWARF looks as follows:
20// (lldb) fr v -R v1
21// (std::variant<int, double, char>) v1 = {
22// std::_SMF_control<std::_Variant_base<int, double, char>, int, double, char>
23// = {
24// std::_Variant_storage<int, double, char> = {
25// = {
26// _Head = 0
27// _Tail = {
28// = {
29// _Head = 2
30// _Tail = {
31// = {
32// _Head = '\0'
33// _Tail = {}
34// }
35// }
36// }
37// }
38// }
39// }
40// _Which = '\x01'
41// }
42// }
43
44ValueObjectSP GetStorageMember(ValueObject &valobj, llvm::StringRef name) {
45 // Find the union
46 ValueObjectSP union_sp = valobj.GetChildAtIndex(0);
47 if (!union_sp)
48 return nullptr;
49 return union_sp->GetChildMemberWithName(name);
50}
51
52ValueObjectSP GetHead(ValueObject &valobj) {
53 return GetStorageMember(valobj, "_Head");
54}
55ValueObjectSP GetTail(ValueObject &valobj) {
56 return GetStorageMember(valobj, "_Tail");
57}
58
59std::optional<int64_t> GetIndexValue(ValueObject &valobj) {
60 ValueObjectSP index_sp = valobj.GetChildMemberWithName("_Which");
61 if (!index_sp)
62 return std::nullopt;
63
64 return {index_sp->GetValueAsSigned(-1)};
65}
66
67ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) {
68 // We need to find the std::_Variant_storage base class.
69
70 // Navigate "down" to std::_Variant_base by finding the holder of "_Which".
71 // This might be down a few levels if a variant member isn't trivially
72 // destructible/copyable/etc.
73 ValueObjectSP which_sp = outer.GetChildMemberWithName("_Which");
74 if (!which_sp)
75 return nullptr;
76 ValueObject *parent = which_sp->GetParent();
77 if (!parent)
78 return nullptr;
79
80 // Now go to std::_Variant_storage.
81 ValueObjectSP container_sp = parent->GetChildAtIndex(0);
82 if (!container_sp)
83 return nullptr;
84
85 for (int64_t i = 0; i < index; i++) {
86 container_sp = GetTail(*container_sp);
87 if (!container_sp)
88 return nullptr;
89 }
90 return container_sp;
91}
92
93} // namespace
94
96 if (auto valobj_sp = valobj.GetNonSyntheticValue()) {
97 return valobj_sp->GetChildMemberWithName("_Which") != nullptr;
98 }
99 return false;
100}
101
103 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
104 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
105 if (!valobj_sp)
106 return false;
107
108 auto index = GetIndexValue(*valobj_sp);
109 if (!index)
110 return false;
111
112 if (*index < 0) {
113 stream.Printf(" No Value");
114 return true;
115 }
116
117 ValueObjectSP storage = GetNthStorage(*valobj_sp, *index);
118 if (!storage)
119 return false;
120 CompilerType storage_type = storage->GetCompilerType();
121 if (!storage_type)
122 return false;
123 // Resolve the typedef
124 if (storage_type.IsTypedefType())
125 storage_type = storage_type.GetTypedefedType();
126
127 CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);
128 if (!active_type) {
129 // PDB: get the type from the head as we don't have template arguments
130 // there.
131 ValueObjectSP head = GetHead(*storage);
132 if (!head)
133 return false;
134 active_type = head->GetCompilerType();
135 if (!active_type)
136 return false;
137 }
138
139 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
140 return true;
141}
142
143namespace {
144class VariantFrontEnd : public SyntheticChildrenFrontEnd {
145public:
146 VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
147 Update();
148 }
149
150 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
151 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
152 if (!optional_idx) {
153 return llvm::createStringError("Type has no child named '%s'",
154 name.AsCString());
155 }
156 return *optional_idx;
157 }
158
159 lldb::ChildCacheState Update() override;
160 llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }
161 ValueObjectSP GetChildAtIndex(uint32_t idx) override;
162
163private:
164 size_t m_size = 0;
165};
166} // namespace
167
168lldb::ChildCacheState VariantFrontEnd::Update() {
169 m_size = 0;
170
171 auto index = GetIndexValue(m_backend);
172 if (index && *index >= 0)
173 m_size = 1;
174
176}
177
178ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) {
179 if (idx >= m_size)
180 return nullptr;
181
182 auto index = GetIndexValue(m_backend);
183 if (!index)
184 return nullptr;
185
186 ValueObjectSP storage_sp = GetNthStorage(m_backend, *index);
187 if (!storage_sp)
188 return nullptr;
189
190 ValueObjectSP head_sp = GetHead(*storage_sp);
191 if (!head_sp)
192 return nullptr;
193
194 return head_sp->Clone(ConstString("Value"));
195}
196
198 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
199 if (valobj_sp)
200 return new VariantFrontEnd(*valobj_sp);
201 return nullptr;
202}
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
ConstString GetDisplayTypeName() const
CompilerType GetTypedefedType() const
If the current object represents a typedef type, get the underlying type.
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
const char * GetCString() const
Get the string value as a C string.
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx, bool can_create=true)
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
std::optional< size_t > ExtractIndexFromString(const char *item_name)
bool MsvcStlVariantSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * MsvcStlVariantSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
bool IsMsvcStlVariant(ValueObject &valobj)
A class that represents a running process on the host machine.
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP