Skip to content

Commit 012bbac

Browse files
committed
[LLDB] Add formatters for MSVC STL unordered containers
1 parent a13712e commit 012bbac

File tree

5 files changed

+111
-11
lines changed

5 files changed

+111
-11
lines changed

lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
3737
MsvcStlSmartPointer.cpp
3838
MsvcStlTuple.cpp
3939
MsvcStlVector.cpp
40+
MsvcStlUnordered.cpp
4041
MSVCUndecoratedNameParser.cpp
4142

4243
LINK_COMPONENTS

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,8 +1434,7 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
14341434
stl_deref_flags,
14351435
"lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
14361436
cpp_category_sp->AddTypeSynthetic(
1437-
"^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1438-
eFormatterMatchRegex,
1437+
"^std::__debug::unordered_(multi)?(map|set)<.+> >$", eFormatterMatchRegex,
14391438
SyntheticChildrenSP(new ScriptedSyntheticChildren(
14401439
stl_deref_flags,
14411440
"lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
@@ -1495,8 +1494,8 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
14951494

14961495
AddCXXSummary(cpp_category_sp,
14971496
lldb_private::formatters::ContainerSizeSummaryProvider,
1498-
"libstdc++ std unordered container summary provider",
1499-
"^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1497+
"libstdc++ debug std unordered container summary provider",
1498+
"^std::__debug::unordered_(multi)?(map|set)<.+> >$",
15001499
stl_summary_flags, true);
15011500

15021501
AddCXXSummary(
@@ -1648,6 +1647,19 @@ GenericForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *children,
16481647
*valobj_sp);
16491648
}
16501649

1650+
static SyntheticChildrenFrontEnd *
1651+
GenericUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1652+
ValueObjectSP valobj_sp) {
1653+
if (!valobj_sp)
1654+
return nullptr;
1655+
1656+
if (IsMsvcStlUnordered(*valobj_sp))
1657+
return MsvcStlUnorderedSyntheticFrontEndCreator(children, valobj_sp);
1658+
return new ScriptedSyntheticChildren::FrontEnd(
1659+
"lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider",
1660+
*valobj_sp);
1661+
}
1662+
16511663
/// Load formatters that are formatting types from more than one STL
16521664
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16531665
if (!cpp_category_sp)
@@ -1712,6 +1724,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
17121724
AddCXXSynthetic(cpp_category_sp, GenericForwardListSyntheticFrontEndCreator,
17131725
"std::forward_list synthetic children",
17141726
"^std::forward_list<.+>(( )?&)?$", stl_synth_flags, true);
1727+
AddCXXSynthetic(cpp_category_sp, GenericUnorderedSyntheticFrontEndCreator,
1728+
"std::unordered container synthetic children",
1729+
"^std::unordered_(multi)?(map|set)<.+> ?>$", stl_synth_flags,
1730+
true);
17151731

17161732
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
17171733
"MSVC STL/libstdc++ std::shared_ptr summary provider",
@@ -1739,6 +1755,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
17391755
TypeSummaryImplSP(new ScriptSummaryFormat(
17401756
stl_summary_flags,
17411757
"lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1758+
AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
1759+
"MSVC STL/libstdc++ std unordered container summary provider",
1760+
"^std::unordered_(multi)?(map|set)<.+> ?>$", stl_summary_flags,
1761+
true);
17421762
}
17431763

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

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::unordered_(multi){map|set}<>
69+
bool IsMsvcStlUnordered(ValueObject &valobj);
70+
SyntheticChildrenFrontEnd *
71+
MsvcStlUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *,
72+
lldb::ValueObjectSP valobj_sp);
73+
6874
} // namespace formatters
6975
} // namespace lldb_private
7076

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===-- MsvcStlUnordered.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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "MsvcStl.h"
10+
#include "lldb/DataFormatters/TypeSynthetic.h"
11+
12+
using namespace lldb;
13+
using namespace lldb_private;
14+
15+
namespace {
16+
17+
class UnorderedFrontEnd : public SyntheticChildrenFrontEnd {
18+
public:
19+
UnorderedFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
20+
Update();
21+
}
22+
23+
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
24+
if (!m_list_sp)
25+
return llvm::createStringError("Missing _List");
26+
return m_list_sp->GetIndexOfChildWithName(name);
27+
}
28+
29+
lldb::ChildCacheState Update() override;
30+
31+
llvm::Expected<uint32_t> CalculateNumChildren() override {
32+
if (!m_list_sp)
33+
return llvm::createStringError("Missing _List");
34+
return m_list_sp->GetNumChildren();
35+
}
36+
37+
ValueObjectSP GetChildAtIndex(uint32_t idx) override {
38+
if (!m_list_sp)
39+
return nullptr;
40+
return m_list_sp->GetChildAtIndex(idx);
41+
}
42+
43+
private:
44+
ValueObjectSP m_list_sp;
45+
};
46+
47+
} // namespace
48+
49+
lldb::ChildCacheState UnorderedFrontEnd::Update() {
50+
m_list_sp = nullptr;
51+
ValueObjectSP list_sp = m_backend.GetChildMemberWithName("_List");
52+
if (!list_sp)
53+
return lldb::ChildCacheState::eRefetch;
54+
m_list_sp = list_sp->GetSyntheticValue();
55+
return lldb::ChildCacheState::eRefetch;
56+
}
57+
58+
bool formatters::IsMsvcStlUnordered(ValueObject &valobj) {
59+
if (auto valobj_sp = valobj.GetNonSyntheticValue())
60+
return valobj_sp->GetChildMemberWithName("_List") != nullptr;
61+
return false;
62+
}
63+
64+
SyntheticChildrenFrontEnd *formatters::MsvcStlUnorderedSyntheticFrontEndCreator(
65+
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
66+
if (valobj_sp)
67+
return new UnorderedFrontEnd(*valobj_sp);
68+
return nullptr;
69+
}

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22
from lldbsuite.test.lldbtest import *
33
from lldbsuite.test import lldbutil
44

5-
USE_LIBSTDCPP = "USE_LIBSTDCPP"
6-
USE_LIBCPP = "USE_LIBCPP"
7-
85

96
class GenericUnorderedDataFormatterTestCase(TestBase):
107
def setUp(self):
118
TestBase.setUp(self)
129
self.namespace = "std"
1310

14-
def do_test_with_run_command(self, stdlib_type):
15-
self.build(dictionary={stdlib_type: "1"})
11+
def do_test_with_run_command(self):
1612
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
1713

1814
lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
@@ -127,8 +123,16 @@ def look_for_content_and_continue(self, var_name, patterns):
127123

128124
@add_test_categories(["libstdcxx"])
129125
def test_with_run_command_libstdcpp(self):
130-
self.do_test_with_run_command(USE_LIBSTDCPP)
126+
self.build(dictionary={"USE_LIBSTDCPP": 1})
127+
self.do_test_with_run_command()
131128

132129
@add_test_categories(["libc++"])
133130
def test_with_run_command_libcpp(self):
134-
self.do_test_with_run_command(USE_LIBCPP)
131+
self.build(dictionary={"USE_LIBCPP": 1})
132+
self.do_test_with_run_command()
133+
134+
@add_test_categories(["msvcstl"])
135+
def test_with_run_command_msvcstl(self):
136+
# No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
137+
self.build()
138+
self.do_test_with_run_command()

0 commit comments

Comments
 (0)