Skip to content

Commit 927e9c7

Browse files
committed
[LLDB] Add formatters for MSVC STL std::optional
1 parent a13712e commit 927e9c7

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,20 +1545,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
15451545
"std::bitset synthetic child", "^std::(__debug::)?bitset<.+>(( )?&)?$",
15461546
stl_deref_flags, true);
15471547

1548-
AddCXXSynthetic(
1549-
cpp_category_sp,
1550-
lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
1551-
"std::optional synthetic child", "^std::optional<.+>(( )?&)?$",
1552-
stl_deref_flags, true);
1553-
15541548
AddCXXSummary(cpp_category_sp,
15551549
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
15561550
"libstdc++ std::coroutine_handle summary provider",
15571551
libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
1558-
AddCXXSummary(cpp_category_sp,
1559-
lldb_private::formatters::GenericOptionalSummaryProvider,
1560-
"libstd++ std::optional summary provider",
1561-
"^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
15621552
}
15631553

15641554
static lldb_private::SyntheticChildrenFrontEnd *
@@ -1648,6 +1638,17 @@ GenericForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *children,
16481638
*valobj_sp);
16491639
}
16501640

1641+
static SyntheticChildrenFrontEnd *
1642+
GenericOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1643+
lldb::ValueObjectSP valobj_sp) {
1644+
if (!valobj_sp)
1645+
return nullptr;
1646+
1647+
if (IsMsvcStlOptional(*valobj_sp))
1648+
return MsvcStlOptionalSyntheticFrontEndCreator(children, valobj_sp);
1649+
return LibStdcppOptionalSyntheticFrontEndCreator(children, valobj_sp);
1650+
}
1651+
16511652
/// Load formatters that are formatting types from more than one STL
16521653
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16531654
if (!cpp_category_sp)
@@ -1664,6 +1665,8 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16641665
SyntheticChildren::Flags stl_synth_flags;
16651666
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
16661667
false);
1668+
SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
1669+
stl_deref_flags.SetFrontEndWantsDereference();
16671670

16681671
using StringElementType = StringPrinter::StringElementType;
16691672

@@ -1712,6 +1715,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
17121715
AddCXXSynthetic(cpp_category_sp, GenericForwardListSyntheticFrontEndCreator,
17131716
"std::forward_list synthetic children",
17141717
"^std::forward_list<.+>(( )?&)?$", stl_synth_flags, true);
1718+
AddCXXSynthetic(cpp_category_sp, GenericOptionalSyntheticFrontEndCreator,
1719+
"std::optional synthetic children",
1720+
"^std::optional<.+>(( )?&)?$", stl_deref_flags, true);
17151721

17161722
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
17171723
"MSVC STL/libstdc++ std::shared_ptr summary provider",
@@ -1739,6 +1745,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
17391745
TypeSummaryImplSP(new ScriptSummaryFormat(
17401746
stl_summary_flags,
17411747
"lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1748+
AddCXXSummary(cpp_category_sp, GenericOptionalSummaryProvider,
1749+
"MSVC STL/libstd++ std::optional summary provider",
1750+
"^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
17421751
}
17431752

17441753
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {

lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Generic.h"
1010
#include "LibCxx.h"
1111
#include "LibStdcpp.h"
12+
#include "MsvcStl.h"
1213
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1314
#include "lldb/DataFormatters/FormattersHelpers.h"
1415
#include "lldb/Target/Target.h"
@@ -32,6 +33,7 @@ class GenericOptionalFrontend : public SyntheticChildrenFrontEnd {
3233
enum class StdLib {
3334
LibCxx,
3435
LibStdcpp,
36+
MsvcStl,
3537
};
3638

3739
GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib);
@@ -77,7 +79,8 @@ lldb::ChildCacheState GenericOptionalFrontend::Update() {
7779
else if (m_stdlib == StdLib::LibStdcpp) {
7880
if (ValueObjectSP payload = m_backend.GetChildMemberWithName("_M_payload"))
7981
engaged_sp = payload->GetChildMemberWithName("_M_engaged");
80-
}
82+
} else if (m_stdlib == StdLib::MsvcStl)
83+
engaged_sp = m_backend.GetChildMemberWithName("_Has_value");
8184

8285
if (!engaged_sp)
8386
return lldb::ChildCacheState::eRefetch;
@@ -114,7 +117,12 @@ ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) {
114117
ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value");
115118
if (candidate)
116119
val_sp = candidate;
117-
}
120+
} else if (m_stdlib == StdLib::MsvcStl)
121+
// Same issue as with LibCxx
122+
val_sp = m_backend.GetChildMemberWithName("_Has_value")
123+
->GetParent()
124+
->GetChildAtIndex(0)
125+
->GetChildMemberWithName("_Value");
118126

119127
if (!val_sp)
120128
return ValueObjectSP();
@@ -143,3 +151,17 @@ SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator(
143151
GenericOptionalFrontend::StdLib::LibCxx);
144152
return nullptr;
145153
}
154+
155+
bool formatters::IsMsvcStlOptional(ValueObject &valobj) {
156+
if (auto valobj_sp = valobj.GetNonSyntheticValue())
157+
return valobj_sp->GetChildMemberWithName("_Has_value") != nullptr;
158+
return false;
159+
}
160+
161+
SyntheticChildrenFrontEnd *formatters::MsvcStlOptionalSyntheticFrontEndCreator(
162+
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
163+
if (valobj_sp)
164+
return new GenericOptionalFrontend(
165+
*valobj_sp, GenericOptionalFrontend::StdLib::MsvcStl);
166+
return nullptr;
167+
}

lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ SyntheticChildrenFrontEnd *
6565
MsvcStlListSyntheticFrontEndCreator(CXXSyntheticChildren *,
6666
lldb::ValueObjectSP valobj_sp);
6767

68+
// MSVC STL std::optional<>
69+
bool IsMsvcStlOptional(ValueObject &valobj);
70+
SyntheticChildrenFrontEnd *
71+
MsvcStlOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,
72+
lldb::ValueObjectSP valobj_sp);
73+
6874
} // namespace formatters
6975
} // namespace lldb_private
7076

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
from lldbsuite.test.lldbtest import *
44
from lldbsuite.test import lldbutil
55

6-
USE_LIBSTDCPP = "USE_LIBSTDCPP"
7-
USE_LIBCPP = "USE_LIBCPP"
8-
96

107
class GenericOptionalDataFormatterTestCase(TestBase):
11-
def do_test_with_run_command(self, stdlib_type):
8+
def do_test_with_run_command(self):
129
"""Test that that file and class static variables display correctly."""
1310

1411
# This is the function to remove the custom formats in order to have a
@@ -21,7 +18,6 @@ def cleanup():
2118

2219
self.addTearDownHook(cleanup)
2320

24-
self.build(dictionary={stdlib_type: "1"})
2521
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
2622

2723
bkpt = self.target().FindBreakpointByID(
@@ -100,7 +96,8 @@ def cleanup():
10096
## We are skipping gcc version less that 5.1 since this test requires -std=c++17
10197
@skipIf(compiler="gcc", compiler_version=["<", "5.1"])
10298
def test_with_run_command_libcpp(self):
103-
self.do_test_with_run_command(USE_LIBCPP)
99+
self.build(dictionary={"USE_LIBCPP": 1})
100+
self.do_test_with_run_command()
104101

105102
@add_test_categories(["libstdcxx"])
106103
## Clang 7.0 is the oldest Clang that can reliably parse newer libc++ versions
@@ -109,4 +106,11 @@ def test_with_run_command_libcpp(self):
109106
## We are skipping gcc version less that 5.1 since this test requires -std=c++17
110107
@skipIf(compiler="gcc", compiler_version=["<", "5.1"])
111108
def test_with_run_command_libstdcpp(self):
112-
self.do_test_with_run_command(USE_LIBSTDCPP)
109+
self.build(dictionary={"USE_LIBSTDCPP": 1})
110+
self.do_test_with_run_command()
111+
112+
@add_test_categories(["msvcstl"])
113+
def test_with_run_command_msvcstl(self):
114+
# No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
115+
self.build()
116+
self.do_test_with_run_command()

0 commit comments

Comments
 (0)