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,12 +4,12 @@ CPlusPlusNameParser.cpp CxxStringTypes.cpp GenericBitset.cpp + GenericOptional.cpp LibCxx.cpp LibCxxAtomic.cpp LibCxxInitializerList.cpp LibCxxList.cpp LibCxxMap.cpp - LibCxxOptional.cpp LibCxxQueue.cpp LibCxxTuple.cpp LibCxxUnorderedMap.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 @@ -35,6 +35,7 @@ #include "BlockPointer.h" #include "CPlusPlusNameParser.h" #include "CxxStringTypes.h" +#include "Generic.h" #include "LibCxx.h" #include "LibCxxAtomic.h" #include "LibCxxVariant.h" @@ -655,7 +656,7 @@ "libc++ std::tuple synthetic children", ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"), stl_synth_flags, true); - AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator, + AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator, "libc++ std::optional synthetic children", ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"), stl_synth_flags, true); @@ -772,7 +773,7 @@ ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_summary_flags, true); AddCXXSummary(cpp_category_sp, - lldb_private::formatters::LibcxxOptionalSummaryProvider, + lldb_private::formatters::GenericOptionalSummaryProvider, "libc++ std::optional summary provider", ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"), stl_summary_flags, true); @@ -918,11 +919,6 @@ 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::multiset<.+> >(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( @@ -946,11 +942,6 @@ stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); - cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression("^std::optional<.+>(( )?&)?$"), - TypeSummaryImplSP(new ScriptSummaryFormat( - stl_summary_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdOptionalSummaryProvider"))); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( RegularExpression("^std::bitset<.+>(( )?&)?$"), TypeSummaryImplSP( @@ -1031,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", @@ -1046,6 +1043,10 @@ "libstdc++ std::weak_ptr summary provider", ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary( + cpp_category_sp, lldb_private::formatters::GenericOptionalSummaryProvider, + "libstd++ std::optional summary provider", + ConstString("^std::optional<.+>(( )?&)?$"), stl_summary_flags, true); } static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/Generic.h b/lldb/source/Plugins/Language/CPlusPlus/Generic.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/Generic.h @@ -0,0 +1,25 @@ +//===-- LibCxx.h -----------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Utility/Stream.h" + +namespace lldb_private { +namespace formatters { + +bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + +} // namespace formatters +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H \ No newline at end of file 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,139 @@ +//===-- 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 "Generic.h" +#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; + +bool lldb_private::formatters::GenericOptionalSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + stream.Printf(" Has Value=%s ", + valobj.GetNumChildren() == 0 ? "false" : "true"); + + return true; +} + +// Synthetic Children Provider +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 engaged_sp; + + if (m_stdlib == StdLib::LibCxx) + engaged_sp = + m_backend.GetChildMemberWithName(ConstString("__engaged_"), true); + else if (m_stdlib == StdLib::LibStdcpp) + engaged_sp = + m_backend.GetChildMemberWithName(ConstString("_M_payload"), true) + ->GetChildMemberWithName(ConstString("_M_engaged"), true); + + if (!engaged_sp) + return false; + + // _M_engaged/__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 = engaged_sp->GetValueAsUnsigned(0) != 0; + + return false; +} + +ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) { + if (!m_has_value) + return ValueObjectSP(); + + ValueObjectSP val_sp; + + if (m_stdlib == StdLib::LibCxx) + // __val_ contains the underlying value of an optional if it has one. + // Currently because it is part of an anonymous union + // GetChildMemberWithName() does not peer through and find it unless we are + // at the parent itself. We can obtain the parent through __engaged_. + val_sp = m_backend.GetChildMemberWithName(ConstString("__engaged_"), true) + ->GetParent() + ->GetChildAtIndex(0, true) + ->GetChildMemberWithName(ConstString("__val_"), true); + else if (m_stdlib == StdLib::LibStdcpp) { + val_sp = m_backend.GetChildMemberWithName(ConstString("_M_payload"), true) + ->GetChildMemberWithName(ConstString("_M_payload"), true); + + // In some implementations, _M_value contains the underlying value of an + // optional, and in other versions, it's in the payload member. + ValueObjectSP candidate = + val_sp->GetChildMemberWithName(ConstString("_M_value"), true); + if (candidate) + val_sp = candidate; + } + + 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/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -170,8 +170,8 @@ lldb::ValueObjectSP); SyntheticChildrenFrontEnd * -LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP valobj_sp); +LibcxxOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); SyntheticChildrenFrontEnd * LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp deleted file mode 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp +++ /dev/null @@ -1,84 +0,0 @@ -//===-- LibCxxOptional.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 "lldb/DataFormatters/FormattersHelpers.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { - -class OptionalFrontEnd : public SyntheticChildrenFrontEnd { -public: - OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { - Update(); - } - - size_t GetIndexOfChildWithName(ConstString name) override { - return formatters::ExtractIndexFromString(name.GetCString()); - } - - bool MightHaveChildren() override { return true; } - bool Update() override; - size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; } - ValueObjectSP GetChildAtIndex(size_t idx) override; - -private: - /// True iff the option contains a value. - bool m_has_value = false; -}; -} // namespace - -bool OptionalFrontEnd::Update() { - ValueObjectSP engaged_sp( - m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)); - - if (!engaged_sp) - return false; - - // __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 = engaged_sp->GetValueAsUnsigned(0) != 0; - - return false; -} - -ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { - if (!m_has_value) - return ValueObjectSP(); - - // __val_ contains the underlying value of an optional if it has one. - // Currently because it is part of an anonymous union GetChildMemberWithName() - // does not peer through and find it unless we are at the parent itself. - // We can obtain the parent through __engaged_. - ValueObjectSP val_sp( - m_backend.GetChildMemberWithName(ConstString("__engaged_"), true) - ->GetParent() - ->GetChildAtIndex(0, true) - ->GetChildMemberWithName(ConstString("__val_"), 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::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP valobj_sp) { - if (valobj_sp) - return new OptionalFrontEnd(*valobj_sp); - 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);