146 lines · cpp
1//===-- GenericInitializerList.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 "lldb/DataFormatters/FormattersHelpers.h"10#include "lldb/Utility/ConstString.h"11#include "lldb/ValueObject/ValueObject.h"12#include <cstddef>13#include <optional>14#include <type_traits>15 16using namespace lldb;17using namespace lldb_private;18 19namespace generic_check {20template <class T>21using size_func = decltype(T::GetSizeMember(std::declval<ValueObject &>()));22template <class T>23using start_func = decltype(T::GetStartMember(std::declval<ValueObject &>()));24namespace {25template <typename...> struct check_func : std::true_type {};26} // namespace27 28template <typename T>29using has_functions = check_func<size_func<T>, start_func<T>>;30} // namespace generic_check31 32struct LibCxx {33 static ValueObjectSP GetStartMember(ValueObject &backend) {34 return backend.GetChildMemberWithName("__begin_");35 }36 37 static ValueObjectSP GetSizeMember(ValueObject &backend) {38 return backend.GetChildMemberWithName("__size_");39 }40};41 42struct LibStdcpp {43 static ValueObjectSP GetStartMember(ValueObject &backend) {44 return backend.GetChildMemberWithName("_M_array");45 }46 47 static ValueObjectSP GetSizeMember(ValueObject &backend) {48 return backend.GetChildMemberWithName("_M_len");49 }50};51 52namespace lldb_private::formatters {53 54template <class StandardImpl>55class GenericInitializerListSyntheticFrontEnd56 : public SyntheticChildrenFrontEnd {57public:58 static_assert(generic_check::has_functions<StandardImpl>::value,59 "Missing Required Functions.");60 61 GenericInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)62 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {63 if (valobj_sp)64 Update();65 }66 67 ~GenericInitializerListSyntheticFrontEnd() override {68 // this needs to stay around because it's a child object who will follow its69 // parent's life cycle70 // delete m_start;71 }72 73 llvm::Expected<uint32_t> CalculateNumChildren() override {74 m_num_elements = 0;75 76 const ValueObjectSP size_sp(StandardImpl::GetSizeMember(m_backend));77 if (size_sp)78 m_num_elements = size_sp->GetValueAsUnsigned(0);79 return m_num_elements;80 }81 82 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {83 if (!m_start)84 return {};85 86 uint64_t offset = static_cast<uint64_t>(idx) * m_element_size;87 offset = offset + m_start->GetValueAsUnsigned(0);88 StreamString name;89 name.Printf("[%" PRIu64 "]", (uint64_t)idx);90 return CreateValueObjectFromAddress(name.GetString(), offset,91 m_backend.GetExecutionContextRef(),92 m_element_type);93 }94 95 lldb::ChildCacheState Update() override {96 m_start = nullptr;97 m_num_elements = 0;98 m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);99 if (!m_element_type.IsValid())100 return lldb::ChildCacheState::eRefetch;101 102 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);103 if (!size_or_err)104 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),105 "{0}");106 else {107 m_element_size = *size_or_err;108 // Store raw pointers or end up with a circular dependency.109 m_start = StandardImpl::GetStartMember(m_backend).get();110 }111 112 return lldb::ChildCacheState::eRefetch;113 }114 115 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {116 if (!m_start) {117 return llvm::createStringError("Type has no child named '%s'",118 name.AsCString());119 }120 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());121 if (!optional_idx) {122 return llvm::createStringError("Type has no child named '%s'",123 name.AsCString());124 }125 return *optional_idx;126 }127 128private:129 ValueObject *m_start = nullptr;130 CompilerType m_element_type;131 uint32_t m_element_size = 0;132 size_t m_num_elements = 0;133};134 135SyntheticChildrenFrontEnd *GenericInitializerListSyntheticFrontEndCreator(136 CXXSyntheticChildren * /*unused*/, lldb::ValueObjectSP valobj_sp) {137 if (!valobj_sp)138 return nullptr;139 140 if (LibCxx::GetStartMember(*valobj_sp) != nullptr)141 return new GenericInitializerListSyntheticFrontEnd<LibCxx>(valobj_sp);142 143 return new GenericInitializerListSyntheticFrontEnd<LibStdcpp>(valobj_sp);144}145} // namespace lldb_private::formatters146