189 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "MsvcStl.h"10#include "lldb/DataFormatters/FormattersHelpers.h"11#include "lldb/Symbol/CompilerType.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 v121// (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 = 027// _Tail = {28// = {29// _Head = 230// _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 union46 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 // -> std::_SMF_control (typedef to std::_Variant_base)71 ValueObjectSP container_sp = outer.GetSP()->GetChildAtIndex(0);72 if (!container_sp)73 return nullptr;74 // -> std::_Variant_storage75 container_sp = container_sp->GetChildAtIndex(0);76 if (!container_sp)77 return nullptr;78 79 for (int64_t i = 0; i < index; i++) {80 container_sp = GetTail(*container_sp);81 if (!container_sp)82 return nullptr;83 }84 return container_sp;85}86 87} // namespace88 89bool formatters::IsMsvcStlVariant(ValueObject &valobj) {90 if (auto valobj_sp = valobj.GetNonSyntheticValue()) {91 return valobj_sp->GetChildMemberWithName("_Which") != nullptr;92 }93 return false;94}95 96bool formatters::MsvcStlVariantSummaryProvider(97 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {98 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());99 if (!valobj_sp)100 return false;101 102 auto index = GetIndexValue(*valobj_sp);103 if (!index)104 return false;105 106 if (*index < 0) {107 stream.Printf(" No Value");108 return true;109 }110 111 ValueObjectSP storage = GetNthStorage(*valobj_sp, *index);112 if (!storage)113 return false;114 CompilerType storage_type = storage->GetCompilerType();115 if (!storage_type)116 return false;117 // Resolve the typedef118 if (storage_type.IsTypedefType())119 storage_type = storage_type.GetTypedefedType();120 121 CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);122 if (!active_type)123 return false;124 125 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";126 return true;127}128 129namespace {130class VariantFrontEnd : public SyntheticChildrenFrontEnd {131public:132 VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {133 Update();134 }135 136 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {137 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());138 if (!optional_idx) {139 return llvm::createStringError("Type has no child named '%s'",140 name.AsCString());141 }142 return *optional_idx;143 }144 145 lldb::ChildCacheState Update() override;146 llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }147 ValueObjectSP GetChildAtIndex(uint32_t idx) override;148 149private:150 size_t m_size = 0;151};152} // namespace153 154lldb::ChildCacheState VariantFrontEnd::Update() {155 m_size = 0;156 157 auto index = GetIndexValue(m_backend);158 if (index && *index >= 0)159 m_size = 1;160 161 return lldb::ChildCacheState::eRefetch;162}163 164ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) {165 if (idx >= m_size)166 return nullptr;167 168 auto index = GetIndexValue(m_backend);169 if (!index)170 return nullptr;171 172 ValueObjectSP storage_sp = GetNthStorage(m_backend, *index);173 if (!storage_sp)174 return nullptr;175 176 ValueObjectSP head_sp = GetHead(*storage_sp);177 if (!head_sp)178 return nullptr;179 180 return head_sp->Clone(ConstString("Value"));181}182 183SyntheticChildrenFrontEnd *formatters::MsvcStlVariantSyntheticFrontEndCreator(184 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {185 if (valobj_sp)186 return new VariantFrontEnd(*valobj_sp);187 return nullptr;188}189