//===-- GenericInitializerList.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Utility/ConstString.h" #include "lldb/ValueObject/ValueObject.h" #include #include #include using namespace lldb; using namespace lldb_private; namespace generic_check { template using size_func = decltype(T::GetSizeMember(std::declval())); template using start_func = decltype(T::GetStartMember(std::declval())); namespace { template struct check_func : std::true_type {}; } // namespace template using has_functions = check_func, start_func>; } // namespace generic_check struct LibCxx { static ValueObjectSP GetStartMember(ValueObject &backend) { return backend.GetChildMemberWithName("__begin_"); } static ValueObjectSP GetSizeMember(ValueObject &backend) { return backend.GetChildMemberWithName("__size_"); } }; struct LibStdcpp { static ValueObjectSP GetStartMember(ValueObject &backend) { return backend.GetChildMemberWithName("_M_array"); } static ValueObjectSP GetSizeMember(ValueObject &backend) { return backend.GetChildMemberWithName("_M_len"); } }; namespace lldb_private::formatters { template class GenericInitializerListSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: static_assert(generic_check::has_functions::value, "Missing Required Functions."); GenericInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { if (valobj_sp) Update(); } ~GenericInitializerListSyntheticFrontEnd() override { // this needs to stay around because it's a child object who will follow its // parent's life cycle // delete m_start; } llvm::Expected CalculateNumChildren() override { m_num_elements = 0; const ValueObjectSP size_sp(StandardImpl::GetSizeMember(m_backend)); if (size_sp) m_num_elements = size_sp->GetValueAsUnsigned(0); return m_num_elements; } lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { if (!m_start) return {}; uint64_t offset = static_cast(idx) * m_element_size; offset = offset + m_start->GetValueAsUnsigned(0); StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); return CreateValueObjectFromAddress(name.GetString(), offset, m_backend.GetExecutionContextRef(), m_element_type); } lldb::ChildCacheState Update() override { m_start = nullptr; m_num_elements = 0; m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0); if (!m_element_type.IsValid()) return lldb::ChildCacheState::eRefetch; llvm::Expected size_or_err = m_element_type.GetByteSize(nullptr); if (!size_or_err) LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(), "{0}"); else { m_element_size = *size_or_err; // Store raw pointers or end up with a circular dependency. m_start = StandardImpl::GetStartMember(m_backend).get(); } return lldb::ChildCacheState::eRefetch; } llvm::Expected GetIndexOfChildWithName(ConstString name) override { if (!m_start) { return llvm::createStringError("Type has no child named '%s'", name.AsCString()); } auto optional_idx = formatters::ExtractIndexFromString(name.GetCString()); if (!optional_idx) { return llvm::createStringError("Type has no child named '%s'", name.AsCString()); } return *optional_idx; } private: ValueObject *m_start = nullptr; CompilerType m_element_type; uint32_t m_element_size = 0; size_t m_num_elements = 0; }; SyntheticChildrenFrontEnd *GenericInitializerListSyntheticFrontEndCreator( CXXSyntheticChildren * /*unused*/, lldb::ValueObjectSP valobj_sp) { if (!valobj_sp) return nullptr; if (LibCxx::GetStartMember(*valobj_sp) != nullptr) return new GenericInitializerListSyntheticFrontEnd(valobj_sp); return new GenericInitializerListSyntheticFrontEnd(valobj_sp); } } // namespace lldb_private::formatters