diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -4,6 +4,7 @@ CPlusPlusNameParser.cpp CxxStringTypes.cpp GenericBitset.cpp + GenericOptional.cpp LibCxx.cpp LibCxxAtomic.cpp LibCxxInitializerList.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -913,11 +913,11 @@ SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_deref_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); - cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression("^std::optional<.+>(( )?&)?$"), - SyntheticChildrenSP(new ScriptedSyntheticChildren( - stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdOptionalSynthProvider"))); + // cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( + // RegularExpression("^std::optional<.+>(( )?&)?$"), + // SyntheticChildrenSP(new ScriptedSyntheticChildren( + // stl_synth_flags, + // "lldb.formatters.cpp.gnu_libstdcpp.StdOptionalSynthProvider"))); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( RegularExpression("^std::multiset<.+> >(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( @@ -1022,6 +1022,12 @@ "std::bitset synthetic child", ConstString("^std::bitset<.+>(( )?&)?$"), stl_deref_flags, true); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator, + "std::optional synthetic child", ConstString("^std::optional<.+>(( )?&)?$"), + stl_deref_flags, true); + AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibStdcppUniquePointerSummaryProvider, "libstdc++ std::unique_ptr summary provider", diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp @@ -0,0 +1,106 @@ +//===-- GenericOptional.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 "LibCxx.h" +#include "LibStdcpp.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + +class GenericOptionalFrontend : public SyntheticChildrenFrontEnd { +public: + enum class StdLib { + LibCxx, + LibStdcpp, + }; + + GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib); + + size_t GetIndexOfChildWithName(ConstString name) override { + return formatters::ExtractIndexFromString(name.GetCString()); + } + + bool MightHaveChildren() override { return true; } + size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; } + + ValueObjectSP GetChildAtIndex(size_t idx) override; + bool Update() override; + +private: + bool m_has_value = false; + StdLib m_stdlib; +}; + +} // namespace + +GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib) + : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { + if (auto target_sp = m_backend.GetTargetSP()) { + Update(); + } +} + + +bool GenericOptionalFrontend::Update() { + ValueObjectSP val_sp = m_backend.GetChildMemberWithName(ConstString("_M_payload"), true); + + if (!val_sp->GetChildMemberWithName(ConstString("_M_engaged"), true)) + return false; + + // _M_engaged is a bool flag and is true if the optional contains a value. + // Converting it to unsigned gives us a size of 1 if it contains a value + // and 0 if not. + m_has_value = val_sp + ->GetChildMemberWithName(ConstString("_M_engaged"), true) + ->GetValueAsUnsigned(0) != 0; + + return false; +} + +ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) { + if (!m_has_value) + return ValueObjectSP(); + + // _M_value contains the underlying value of an optional if it has one. + ValueObjectSP val_sp( + m_backend.GetChildMemberWithName(ConstString("_M_payload"), true) + ->GetChildAtIndex(0, true) + ->GetChildMemberWithName(ConstString("_M_payload"), true) + ->GetChildMemberWithName(ConstString("_M_value"), true)); + + if (!val_sp) + return ValueObjectSP(); + + CompilerType holder_type = val_sp->GetCompilerType(); + + if (!holder_type) + return ValueObjectSP(); + + return val_sp->Clone(ConstString("Value")); +} + +SyntheticChildrenFrontEnd *formatters::LibStdcppOptionalSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new GenericOptionalFrontend(*valobj_sp, + GenericOptionalFrontend::StdLib::LibStdcpp); + return nullptr; +} + +// SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( +// CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { +// if (valobj_sp) +// return new GenericOptionalFrontend(*valobj_sp, +// GenericOptionalFrontend::StdLib::LibCxx); +// return nullptr; +// } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -45,6 +45,10 @@ LibStdcppBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibStdcppOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);