https://github.com/da-viper created https://github.com/llvm/llvm-project/pull/140727
Fixes #60841 >From f7d90b3e3ec052adc10ca79459249409a5ed69c2 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <yerimy...@gmail.com> Date: Sun, 18 May 2025 09:55:25 +0100 Subject: [PATCH 1/5] [lldb] optionally match the `__debug` namespace for libstdc++ containers. If libstdc++ is compiled with `_GLIBCXX_DEBUG` flag it puts the containers in the namespace `std::__debug`. this causes the summary and synthetic formatters not to match the types. The formatters is updated to optionally match the `__debug::`. The formatters now clashed with the libc++ containers namespace regex which uses `std::__1` namespace The libc++ formatter is loaded first, then the libstdc++ since the priority of the formatters in lldb is the last one added. Fixes #60841 --- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 136 +++++++++--------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 542f13bef23e7..f6fc7e7114953 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1449,104 +1449,110 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_deref_flags.SetFrontEndWantsDereference(); cpp_category_sp->AddTypeSynthetic( - "^std::vector<.+>(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?vector<.+>(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::map<.+> >(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?map<.+> >(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::deque<.+>(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug)?deque<.+>(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::set<.+> >(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?set<.+> >(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::multimap<.+> >(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?multimap<.+> >(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::multiset<.+> >(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?multiset<.+> >(( )?&)?$", eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::unordered_(multi)?(map|set)<.+> >$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$", + eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::(__cxx11::)?list<.+>(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$", + eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_deref_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")); cpp_category_sp->AddTypeSynthetic( - "^std::(__cxx11::)?forward_list<.+>(( )?&)?$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$", + eFormatterMatchRegex, + std::make_shared<ScriptedSyntheticChildren>( stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")); cpp_category_sp->AddTypeSynthetic( "^std::variant<.+>$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( + std::make_shared<ScriptedSyntheticChildren>( stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider")); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); - cpp_category_sp->AddTypeSummary("^std::bitset<.+>(( )?&)?$", - eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::vector<.+>(( )?&)?$", + cpp_category_sp->AddTypeSummary("^std::(__debug::)?bitset<.+>(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::map<.+> >(( )?&)?$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?vector<.+>(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::set<.+> >(( )?&)?$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?map<.+> >(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::deque<.+>(( )?&)?$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?set<.+> >(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::multimap<.+> >(( )?&)?$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?deque<.+>(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::multiset<.+> >(( )?&)?$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?multimap<.+> >(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::unordered_(multi)?(map|set)<.+> >$", + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary("^std::(__debug::)?multiset<.+> >(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); - cpp_category_sp->AddTypeSummary("^std::(__cxx11::)?list<.+>(( )?&)?$", - eFormatterMatchRegex, - TypeSummaryImplSP(new StringSummaryFormat( - stl_summary_flags, "size=${svar%#}"))); + std::make_shared<StringSummaryFormat>( + stl_summary_flags, "size=${svar%#}")); + cpp_category_sp->AddTypeSummary( + "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$", + eFormatterMatchRegex, + std::make_shared<StringSummaryFormat>(stl_summary_flags, + "size=${svar%#}")); cpp_category_sp->AddTypeSummary( - "^std::(__cxx11::)?forward_list<.+>(( )?&)?$", eFormatterMatchRegex, - TypeSummaryImplSP(new ScriptSummaryFormat( + "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$", + eFormatterMatchRegex, + std::make_shared<StringSummaryFormat>(stl_summary_flags, + "size=${svar%#}")); + cpp_category_sp->AddTypeSummary( + "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$", + eFormatterMatchRegex, + std::make_shared<ScriptSummaryFormat>( stl_summary_flags, - "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")); cpp_category_sp->AddTypeSummary( "^std::variant<.+>$", eFormatterMatchRegex, - TypeSummaryImplSP(new ScriptSummaryFormat( + std::make_shared<ScriptSummaryFormat>( stl_summary_flags, - "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider"))); + "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider")); AddCXXSynthetic( cpp_category_sp, @@ -1592,7 +1598,7 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator, - "std::bitset synthetic child", "^std::bitset<.+>(( )?&)?$", + "std::bitset synthetic child", "^std::(__debug::)?bitset<.+>(( )?&)?$", stl_deref_flags, true); AddCXXSynthetic( @@ -1731,8 +1737,8 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { DataVisualization::Categories::GetCategory(ConstString(GetPluginName()), g_category); if (g_category) { - LoadLibStdcppFormatters(g_category); LoadLibCxxFormatters(g_category); + LoadLibStdcppFormatters(g_category); LoadSystemFormatters(g_category); } }); >From b18de60fe04e65afd30429dc6b23aba5924b2a73 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <yerimy...@gmail.com> Date: Sun, 18 May 2025 10:05:53 +0100 Subject: [PATCH 2/5] [lldb] Update test crashes because it depended on the order of the strings. --- .../data-formatter-categories/TestDataFormatterCategories.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py b/lldb/test/API/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py index f602d017f28b7..344fbb8994ba5 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py @@ -335,5 +335,7 @@ def cleanup(): # and also validate that one can print formatters for a language self.expect( - "type summary list -l c++", substrs=["vector", "map", "list", "string"] + "type summary list -l c++", + substrs=["vector", "map", "list", "string"], + ordered=False ) >From 975b2dd78becb988375d20deae80a311eb0b21d4 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <yerimy...@gmail.com> Date: Sun, 18 May 2025 10:22:37 +0100 Subject: [PATCH 3/5] [lldb] Update std::vector test --- .../vector/DataFormatterStdVector.py | 219 ++++++++++++++++++ .../libstdcpp/vector/Makefile | 8 + .../vector/TestDataFormatterStdVector.py | 209 +---------------- .../vector/TestDataFormatterStdVectorDebug.py | 16 ++ 4 files changed, 250 insertions(+), 202 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/DataFormatterStdVector.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVectorDebug.py diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/DataFormatterStdVector.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/DataFormatterStdVector.py new file mode 100644 index 0000000000000..07fb2a222f321 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/DataFormatterStdVector.py @@ -0,0 +1,219 @@ +""" +Test lldb data formatter subsystem. +""" + +from abc import abstractmethod +from lldbsuite.test.lldbtest import ( + CURRENT_EXECUTABLE_SET, + RUN_SUCCEEDED, + STOPPED_DUE_TO_BREAKPOINT, + TestBase, + line_number, +) +from lldbsuite.test import lldbutil + + +class StdVectorDataFormatterBase(TestBase): + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number("main.cpp", "// Set break point at this line.") + + @abstractmethod + def test_with_run_command(self): + pass + + def with_run_command(self, artifact_name: str): + """Test that that file and class static variables display correctly.""" + self.build() + self.runCmd( + "file " + self.getBuildArtifact(artifact_name), CURRENT_EXECUTABLE_SET + ) + + lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.") + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd("type format clear", check=False) + self.runCmd("type summary clear", check=False) + self.runCmd("type filter clear", check=False) + self.runCmd("type synth clear", check=False) + self.runCmd("settings set target.max-children-count 256", check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + # empty vectors (and storage pointers SHOULD BOTH BE NULL..) + self.expect("frame variable numbers", substrs=["numbers = size=0"]) + + self.runCmd("c") + + # first value added + self.expect( + "frame variable numbers", substrs=["numbers = size=1", "[0] = 1", "}"] + ) + + # add some more data + self.runCmd("c") + + self.expect( + "frame variable numbers", + substrs=[ + "numbers = size=4", + "[0] = 1", + "[1] = 12", + "[2] = 123", + "[3] = 1234", + "}", + ], + ) + + self.expect( + "expression numbers", + substrs=[ + "$", + "size=4", + "[0] = 1", + "[1] = 12", + "[2] = 123", + "[3] = 1234", + "}", + ], + ) + + # check access to synthetic children + self.runCmd( + 'type summary add --summary-string "item 0 is ${var[0]}" std::int_vect int_vect' + ) + self.expect("frame variable numbers", substrs=["item 0 is 1"]) + + self.runCmd( + 'type summary add --summary-string "item 0 is ${svar[0]}" std::int_vect int_vect' + ) + # import time + # time.sleep(19) + self.expect("frame variable numbers", substrs=["item 0 is 1"]) + # move on with synths + self.runCmd("type summary delete std::int_vect") + self.runCmd("type summary delete int_vect") + + # add some more data + self.runCmd("c") + + self.expect( + "frame variable numbers", + substrs=[ + "numbers = size=7", + "[0] = 1", + "[1] = 12", + "[2] = 123", + "[3] = 1234", + "[4] = 12345", + "[5] = 123456", + "[6] = 1234567", + "}", + ], + ) + + self.expect( + "expression numbers", + substrs=[ + "$", + "size=7", + "[0] = 1", + "[1] = 12", + "[2] = 123", + "[3] = 1234", + "[4] = 12345", + "[5] = 123456", + "[6] = 1234567", + "}", + ], + ) + + # check access-by-index + self.expect("frame variable numbers[0]", substrs=["1"]) + self.expect("frame variable numbers[1]", substrs=["12"]) + self.expect("frame variable numbers[2]", substrs=["123"]) + self.expect("frame variable numbers[3]", substrs=["1234"]) + + # but check that expression does not rely on us + # (when expression gets to call into STL code correctly, we will have to find + # another way to check this) + self.expect( + "expression numbers[6]", matching=False, error=True, substrs=["1234567"] + ) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("numbers").MightHaveChildren(), + "numbers.MightHaveChildren() says False for non empty!", + ) + + # clear out the vector and see that we do the right thing once again + self.runCmd("c") + + self.expect("frame variable numbers", substrs=["numbers = size=0"]) + + self.runCmd("c") + + # first value added + self.expect( + "frame variable numbers", substrs=["numbers = size=1", "[0] = 7", "}"] + ) + + # check if we can display strings + self.runCmd("c") + + self.expect("frame variable strings", substrs=["goofy", "is", "smart"]) + + self.expect("expression strings", substrs=["goofy", "is", "smart"]) + + # test summaries based on synthetic children + self.runCmd( + 'type summary add std::string_vect string_vect --summary-string "vector has ${svar%#} items" -e' + ) + self.expect( + "frame variable strings", + substrs=["vector has 3 items", "goofy", "is", "smart"], + ) + + self.expect( + "expression strings", substrs=["vector has 3 items", "goofy", "is", "smart"] + ) + + self.runCmd("c") + + self.expect("frame variable strings", substrs=["vector has 4 items"]) + + # check access-by-index + self.expect("frame variable strings[0]", substrs=["goofy"]) + self.expect("frame variable strings[1]", substrs=["is"]) + + # but check that expression does not rely on us + # (when expression gets to call into STL code correctly, we will have to find + # another way to check this) + self.expect( + "expression strings[0]", matching=False, error=True, substrs=["goofy"] + ) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("strings").MightHaveChildren(), + "strings.MightHaveChildren() says False for non empty!", + ) + + self.runCmd("c") + + self.expect("frame variable strings", substrs=["vector has 0 items"]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/Makefile index 654e4b15bd568..6bb9503378934 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/Makefile +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/Makefile @@ -3,4 +3,12 @@ CXX_SOURCES := main.cpp CXXFLAGS := -O0 USE_LIBSTDCPP := 1 +all: debug_a.out + include Makefile.rules + +debug_main.o: main.cpp + $(CXX) $(PCHFLAGS) $(CXXFLAGS) -D_GLIBCXX_DEBUG -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +debug_a.out: debug_main.o + $(LD) debug_main.o $(LDFLAGS) -o debug_a.out \ No newline at end of file diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py index e7d3ab3916927..b824a5024197a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py @@ -1,211 +1,16 @@ """ -Test lldb data formatter subsystem. +Test lldb data formatter subsystem for std::vector. """ +from typing import override -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil +from lldbsuite.test.decorators import add_test_categories, expectedFailureAll +from DataFormatterStdVector import StdVectorDataFormatterBase -class StdVectorDataFormatterTestCase(TestBase): - def setUp(self): - # Call super's setUp(). - TestBase.setUp(self) - # Find the line number to break at. - self.line = line_number("main.cpp", "// Set break point at this line.") - +class NoDebugTestCase(StdVectorDataFormatterBase): @add_test_categories(["libstdcxx"]) @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc") + @override def test_with_run_command(self): - """Test that that file and class static variables display correctly.""" - self.build() - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - - lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.") - - self.runCmd("run", RUN_SUCCEEDED) - - # The stop reason of the thread should be breakpoint. - self.expect( - "thread list", - STOPPED_DUE_TO_BREAKPOINT, - substrs=["stopped", "stop reason = breakpoint"], - ) - - # This is the function to remove the custom formats in order to have a - # clean slate for the next test case. - def cleanup(): - self.runCmd("type format clear", check=False) - self.runCmd("type summary clear", check=False) - self.runCmd("type filter clear", check=False) - self.runCmd("type synth clear", check=False) - self.runCmd("settings set target.max-children-count 256", check=False) - - # Execute the cleanup function during test case tear down. - self.addTearDownHook(cleanup) - - # empty vectors (and storage pointers SHOULD BOTH BE NULL..) - self.expect("frame variable numbers", substrs=["numbers = size=0"]) - - self.runCmd("c") - - # first value added - self.expect( - "frame variable numbers", substrs=["numbers = size=1", "[0] = 1", "}"] - ) - - # add some more data - self.runCmd("c") - - self.expect( - "frame variable numbers", - substrs=[ - "numbers = size=4", - "[0] = 1", - "[1] = 12", - "[2] = 123", - "[3] = 1234", - "}", - ], - ) - - self.expect( - "expression numbers", - substrs=[ - "$", - "size=4", - "[0] = 1", - "[1] = 12", - "[2] = 123", - "[3] = 1234", - "}", - ], - ) - - # check access to synthetic children - self.runCmd( - 'type summary add --summary-string "item 0 is ${var[0]}" std::int_vect int_vect' - ) - self.expect("frame variable numbers", substrs=["item 0 is 1"]) - - self.runCmd( - 'type summary add --summary-string "item 0 is ${svar[0]}" std::int_vect int_vect' - ) - # import time - # time.sleep(19) - self.expect("frame variable numbers", substrs=["item 0 is 1"]) - # move on with synths - self.runCmd("type summary delete std::int_vect") - self.runCmd("type summary delete int_vect") - - # add some more data - self.runCmd("c") - - self.expect( - "frame variable numbers", - substrs=[ - "numbers = size=7", - "[0] = 1", - "[1] = 12", - "[2] = 123", - "[3] = 1234", - "[4] = 12345", - "[5] = 123456", - "[6] = 1234567", - "}", - ], - ) - - self.expect( - "expression numbers", - substrs=[ - "$", - "size=7", - "[0] = 1", - "[1] = 12", - "[2] = 123", - "[3] = 1234", - "[4] = 12345", - "[5] = 123456", - "[6] = 1234567", - "}", - ], - ) - - # check access-by-index - self.expect("frame variable numbers[0]", substrs=["1"]) - self.expect("frame variable numbers[1]", substrs=["12"]) - self.expect("frame variable numbers[2]", substrs=["123"]) - self.expect("frame variable numbers[3]", substrs=["1234"]) - - # but check that expression does not rely on us - # (when expression gets to call into STL code correctly, we will have to find - # another way to check this) - self.expect( - "expression numbers[6]", matching=False, error=True, substrs=["1234567"] - ) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("numbers").MightHaveChildren(), - "numbers.MightHaveChildren() says False for non empty!", - ) - - # clear out the vector and see that we do the right thing once again - self.runCmd("c") - - self.expect("frame variable numbers", substrs=["numbers = size=0"]) - - self.runCmd("c") - - # first value added - self.expect( - "frame variable numbers", substrs=["numbers = size=1", "[0] = 7", "}"] - ) - - # check if we can display strings - self.runCmd("c") - - self.expect("frame variable strings", substrs=["goofy", "is", "smart"]) - - self.expect("expression strings", substrs=["goofy", "is", "smart"]) - - # test summaries based on synthetic children - self.runCmd( - 'type summary add std::string_vect string_vect --summary-string "vector has ${svar%#} items" -e' - ) - self.expect( - "frame variable strings", - substrs=["vector has 3 items", "goofy", "is", "smart"], - ) - - self.expect( - "expression strings", substrs=["vector has 3 items", "goofy", "is", "smart"] - ) - - self.runCmd("c") - - self.expect("frame variable strings", substrs=["vector has 4 items"]) - - # check access-by-index - self.expect("frame variable strings[0]", substrs=["goofy"]) - self.expect("frame variable strings[1]", substrs=["is"]) - - # but check that expression does not rely on us - # (when expression gets to call into STL code correctly, we will have to find - # another way to check this) - self.expect( - "expression strings[0]", matching=False, error=True, substrs=["goofy"] - ) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("strings").MightHaveChildren(), - "strings.MightHaveChildren() says False for non empty!", - ) - - self.runCmd("c") - - self.expect("frame variable strings", substrs=["vector has 0 items"]) + self.with_run_command("a.out") diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVectorDebug.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVectorDebug.py new file mode 100644 index 0000000000000..0007d4bff42cc --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVectorDebug.py @@ -0,0 +1,16 @@ +""" +Test lldb data formatter subsystem for std::vector with -D_GLIBCXX_DEBUG flag +""" + +from typing import override + +from lldbsuite.test.decorators import add_test_categories, expectedFailureAll +from DataFormatterStdVector import StdVectorDataFormatterBase + + +class WithDebugTestCase(StdVectorDataFormatterBase): + @add_test_categories(["libstdcxx"]) + @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc") + @override + def test_with_run_command(self): + self.with_run_command("debug_a.out") >From 52954c6d50a607a4504644a5ef2dfab5c1402f63 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <yerimy...@gmail.com> Date: Sun, 18 May 2025 10:39:26 +0100 Subject: [PATCH 4/5] [lldb] Update std::vector<bool> test --- .../libstdcpp/vbool/DataFormatterStdVBool.py | 79 +++++++++++++++++++ .../libstdcpp/vbool/Makefile | 10 ++- .../vbool/TestDataFormatterStdVBool.py | 76 ++---------------- .../TestDataFormatterStdVBoolWithDebug.py | 14 ++++ 4 files changed, 109 insertions(+), 70 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/DataFormatterStdVBool.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBoolWithDebug.py diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/DataFormatterStdVBool.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/DataFormatterStdVBool.py new file mode 100644 index 0000000000000..2f26659223130 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/DataFormatterStdVBool.py @@ -0,0 +1,79 @@ +""" +Test lldb data formatter subsystem. +""" + +from abc import abstractmethod +from lldbsuite.test.decorators import add_test_categories +from lldbsuite.test.lldbtest import CURRENT_EXECUTABLE_SET, RUN_SUCCEEDED, STOPPED_DUE_TO_BREAKPOINT, TestBase, \ + line_number +from lldbsuite.test import lldbutil + + +class StdVBoolDataFormatterBase(TestBase): + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number("main.cpp", "// Set break point at this line.") + + @abstractmethod + def test_with_run_command(self): + pass + + def with_run_command(self, artifact_name: str): + """Test that that file and class static variables display correctly.""" + self.build() + self.runCmd("file " + self.getBuildArtifact(artifact_name), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=-1 + ) + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd("type format clear", check=False) + self.runCmd("type summary clear", check=False) + self.runCmd("type filter clear", check=False) + self.runCmd("type synth clear", check=False) + self.runCmd("settings set target.max-children-count 256", check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.expect( + "frame variable vBool", + substrs=[ + "size=49", + "[0] = false", + "[1] = true", + "[18] = false", + "[27] = true", + "[36] = false", + "[47] = true", + "[48] = true", + ], + ) + + self.expect( + "expr vBool", + substrs=[ + "size=49", + "[0] = false", + "[1] = true", + "[18] = false", + "[27] = true", + "[36] = false", + "[47] = true", + "[48] = true", + ], + ) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/Makefile index c825977b1a5dc..6bb9503378934 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/Makefile +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/Makefile @@ -1,6 +1,14 @@ CXX_SOURCES := main.cpp -CFLAGS_EXTRAS := -O0 +CXXFLAGS := -O0 USE_LIBSTDCPP := 1 +all: debug_a.out + include Makefile.rules + +debug_main.o: main.cpp + $(CXX) $(PCHFLAGS) $(CXXFLAGS) -D_GLIBCXX_DEBUG -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +debug_a.out: debug_main.o + $(LD) debug_main.o $(LDFLAGS) -o debug_a.out \ No newline at end of file diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBool.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBool.py index 696d1c672192d..44bed4b8b15ab 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBool.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBool.py @@ -1,76 +1,14 @@ """ -Test lldb data formatter subsystem. +Test lldb data formatter subsystem for std::vector<bool> """ +from typing import override +from lldbsuite.test.decorators import add_test_categories +from DataFormatterStdVBool import StdVBoolDataFormatterBase -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil - - -class StdVBoolDataFormatterTestCase(TestBase): - def setUp(self): - # Call super's setUp(). - TestBase.setUp(self) - # Find the line number to break at. - self.line = line_number("main.cpp", "// Set break point at this line.") +class StdVBoolDataFormatter(StdVBoolDataFormatterBase): @add_test_categories(["libstdcxx"]) + @override def test_with_run_command(self): - """Test that that file and class static variables display correctly.""" - self.build() - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - - lldbutil.run_break_set_by_file_and_line( - self, "main.cpp", self.line, num_expected_locations=-1 - ) - - self.runCmd("run", RUN_SUCCEEDED) - - # The stop reason of the thread should be breakpoint. - self.expect( - "thread list", - STOPPED_DUE_TO_BREAKPOINT, - substrs=["stopped", "stop reason = breakpoint"], - ) - - # This is the function to remove the custom formats in order to have a - # clean slate for the next test case. - def cleanup(): - self.runCmd("type format clear", check=False) - self.runCmd("type summary clear", check=False) - self.runCmd("type filter clear", check=False) - self.runCmd("type synth clear", check=False) - self.runCmd("settings set target.max-children-count 256", check=False) - - # Execute the cleanup function during test case tear down. - self.addTearDownHook(cleanup) - - self.expect( - "frame variable vBool", - substrs=[ - "size=49", - "[0] = false", - "[1] = true", - "[18] = false", - "[27] = true", - "[36] = false", - "[47] = true", - "[48] = true", - ], - ) - - self.expect( - "expr vBool", - substrs=[ - "size=49", - "[0] = false", - "[1] = true", - "[18] = false", - "[27] = true", - "[36] = false", - "[47] = true", - "[48] = true", - ], - ) + self.with_run_command("a.out") diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBoolWithDebug.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBoolWithDebug.py new file mode 100644 index 0000000000000..0210d9cf75c7e --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBoolWithDebug.py @@ -0,0 +1,14 @@ +""" +Test lldb data formatter subsystem for std::vector<bool> with flag "_GLIBCXX_DEBUG" +""" + +from typing import override +from lldbsuite.test.decorators import add_test_categories +from DataFormatterStdVBool import StdVBoolDataFormatterBase + + +class StdVBoolDataFormatterWithDebug(StdVBoolDataFormatterBase): + @add_test_categories(["libstdcxx"]) + @override + def test_with_run_command(self): + self.with_run_command("debug_a.out") >From a9e861455b43992d0afae68b600e662932d2a219 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <yerimy...@gmail.com> Date: Sun, 18 May 2025 12:38:58 +0100 Subject: [PATCH 5/5] [lldb] Update std::map test --- .../libstdcpp/map/DataFormatterStdMap.py | 300 ++++++++++++++++++ .../data-formatter-stl/libstdcpp/map/Makefile | 8 + .../libstdcpp/map/TestDataFormatterStdMap.py | 293 +---------------- .../map/TestDataFormatterStdMapWithDebug.py | 14 + 4 files changed, 329 insertions(+), 286 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/DataFormatterStdMap.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMapWithDebug.py diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/DataFormatterStdMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/DataFormatterStdMap.py new file mode 100644 index 0000000000000..f6dac643b95a0 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/DataFormatterStdMap.py @@ -0,0 +1,300 @@ +""" +Test lldb data formatter subsystem. +""" + +from abc import abstractmethod +from lldbsuite.test.decorators import add_test_categories, expectedFailureAll +from lldbsuite.test.lldbtest import ( + CURRENT_EXECUTABLE_SET, + RUN_SUCCEEDED, + STOPPED_DUE_TO_BREAKPOINT, + TestBase, + line_number, +) +from lldbsuite.test import lldbutil + + +class StdMapDataFormatterBase(TestBase): + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number("main.cpp", "// Set break point at this line.") + + @abstractmethod + def test_with_run_command(self): + pass + + def with_run_command(self, artifact_name: str, namespace: str = ""): + """Test that that file and class static variables display correctly.""" + self.build() + self.runCmd("file " + self.getBuildArtifact(artifact_name), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.") + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd("type format clear", check=False) + self.runCmd("type summary clear", check=False) + self.runCmd("type filter clear", check=False) + self.runCmd("type synth clear", check=False) + self.runCmd("settings set target.max-children-count 256", check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.runCmd("frame variable ii --show-types") + + self.runCmd( + f'type summary add -x "std::{namespace}map<" --summary-string "map has ${{svar%#}} items" -e' + ) + + self.expect("frame variable ii", substrs=["map has 0 items", "{}"]) + + self.runCmd("c") + + self.expect( + "frame variable ii", + substrs=[ + "map has 2 items", + "[0] = ", + "first = 0", + "second = 0", + "[1] = ", + "first = 1", + "second = 1", + ], + ) + + self.runCmd("c") + + self.expect( + "frame variable ii", + substrs=[ + "map has 4 items", + "[2] = ", + "first = 2", + "second = 0", + "[3] = ", + "first = 3", + "second = 1", + ], + ) + + self.runCmd("c") + + self.expect( + "frame variable ii", + substrs=[ + "map has 9 items", + "[5] = ", + "first = 5", + "second = 0", + "[7] = ", + "first = 7", + "second = 1", + ], + ) + + self.expect( + "expression ii", + substrs=[ + "map has 9 items", + "[5] = ", + "first = 5", + "second = 0", + "[7] = ", + "first = 7", + "second = 1", + ], + ) + + # check access-by-index + self.expect("frame variable ii[0]", substrs=["first = 0", "second = 0"]) + self.expect("frame variable ii[3]", substrs=["first =", "second ="]) + + self.expect("frame variable ii[8]", matching=True, substrs=["1234567"]) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("ii").MightHaveChildren(), + "ii.MightHaveChildren() says False for non empty!", + ) + + # check that the expression parser does not make use of + # synthetic children instead of running code + # TOT clang has a fix for this, which makes the expression command here succeed + # since this would make the test fail or succeed depending on clang version in use + # this is safer commented for the time being + # self.expect("expression ii[8]", matching=False, error=True, + # substrs = ['1234567']) + + self.runCmd("c") + + self.expect("frame variable ii", substrs=["map has 0 items", "{}"]) + + self.runCmd("frame variable si --show-types") + + self.expect("frame variable si", substrs=["map has 0 items", "{}"]) + + self.runCmd("c") + + self.expect( + "frame variable si", + substrs=["map has 1 items", "[0] = ", 'first = "zero"', "second = 0"], + ) + + self.runCmd("c") + + self.expect( + "frame variable si", + substrs=[ + "map has 5 items", + '[0] = (first = "four", second = 4)', + '[1] = (first = "one", second = 1)', + '[2] = (first = "three", second = 3)', + '[3] = (first = "two", second = 2)', + '[4] = (first = "zero", second = 0)', + ], + ) + + self.expect( + "expression si", + substrs=[ + "map has 5 items", + '[0] = (first = "four", second = 4)', + '[1] = (first = "one", second = 1)', + '[2] = (first = "three", second = 3)', + '[3] = (first = "two", second = 2)', + '[4] = (first = "zero", second = 0)', + ], + ) + + # check access-by-index + self.expect("frame variable si[0]", substrs=["first = ", "four", "second = 4"]) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("si").MightHaveChildren(), + "si.MightHaveChildren() says False for non empty!", + ) + + # check that the expression parser does not make use of + # synthetic children instead of running code + # TOT clang has a fix for this, which makes the expression command here succeed + # since this would make the test fail or succeed depending on clang version in use + # this is safer commented for the time being + # self.expect("expression si[0]", matching=False, error=True, + # substrs = ['first = ', 'zero']) + + self.runCmd("c") + + self.expect("frame variable si", substrs=["map has 0 items", "{}"]) + + self.runCmd("frame variable is --show-types") + + self.expect("frame variable is", substrs=["map has 0 items", "{}"]) + + self.runCmd("c") + + self.expect( + "frame variable is", + substrs=[ + "map has 4 items", + '[0] = (first = 1, second = "is")', + '[1] = (first = 2, second = "smart")', + '[2] = (first = 3, second = "!!!")', + '[3] = (first = 85, second = "goofy")', + ], + ) + + self.expect( + "expression is", + substrs=[ + "map has 4 items", + '[0] = (first = 1, second = "is")', + '[1] = (first = 2, second = "smart")', + '[2] = (first = 3, second = "!!!")', + '[3] = (first = 85, second = "goofy")', + ], + ) + + # check access-by-index + self.expect("frame variable is[0]", substrs=["first = ", "second ="]) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("is").MightHaveChildren(), + "is.MightHaveChildren() says False for non empty!", + ) + + # check that the expression parser does not make use of + # synthetic children instead of running code + # TOT clang has a fix for this, which makes the expression command here succeed + # since this would make the test fail or succeed depending on clang version in use + # this is safer commented for the time being + # self.expect("expression is[0]", matching=False, error=True, + # substrs = ['first = ', 'goofy']) + + self.runCmd("c") + + self.expect("frame variable is", substrs=["map has 0 items", "{}"]) + + self.runCmd("frame variable ss --show-types") + + self.expect("frame variable ss", substrs=["map has 0 items", "{}"]) + + self.runCmd("c") + + self.expect( + "frame variable ss", + substrs=[ + "map has 4 items", + '[0] = (first = "a Mac..", second = "..is always a Mac!")', + '[1] = (first = "casa", second = "house")', + '[2] = (first = "ciao", second = "hello")', + '[3] = (first = "gatto", second = "cat")', + ], + ) + + self.expect( + "expression ss", + substrs=[ + "map has 4 items", + '[0] = (first = "a Mac..", second = "..is always a Mac!")', + '[1] = (first = "casa", second = "house")', + '[2] = (first = "ciao", second = "hello")', + '[3] = (first = "gatto", second = "cat")', + ], + ) + + # check access-by-index + self.expect("frame variable ss[3]", substrs=["gatto", "cat"]) + + # check that MightHaveChildren() gets it right + self.assertTrue( + self.frame().FindVariable("ss").MightHaveChildren(), + "ss.MightHaveChildren() says False for non empty!", + ) + + # check that the expression parser does not make use of + # synthetic children instead of running code + # TOT clang has a fix for this, which makes the expression command here succeed + # since this would make the test fail or succeed depending on clang version in use + # this is safer commented for the time being + # self.expect("expression ss[3]", matching=False, error=True, + # substrs = ['gatto']) + + self.runCmd("c") + + self.expect("frame variable ss", substrs=["map has 0 items", "{}"]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/Makefile index bf8e6b8703f36..a54f061fdf541 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/Makefile +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/Makefile @@ -2,4 +2,12 @@ CXX_SOURCES := main.cpp USE_LIBSTDCPP := 1 +all: debug_a.out + include Makefile.rules + +debug_main.o: main.cpp + $(CXX) $(PCHFLAGS) $(CXXFLAGS) -D_GLIBCXX_DEBUG -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +debug_a.out: debug_main.o + $(LD) debug_main.o $(LDFLAGS) -o debug_a.out \ No newline at end of file diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMap.py index 0cdc213841be6..9b8a9fa9e3054 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMap.py @@ -1,293 +1,14 @@ """ -Test lldb data formatter subsystem. +Test lldb data formatter subsystem for std::map """ +from typing import override +from DataFormatterStdMap import StdMapDataFormatterBase +from lldbsuite.test.decorators import add_test_categories, expectedFailureAll -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil - - -class StdMapDataFormatterTestCase(TestBase): - def setUp(self): - # Call super's setUp(). - TestBase.setUp(self) - # Find the line number to break at. - self.line = line_number("main.cpp", "// Set break point at this line.") - +class StdMapDataFormatter(StdMapDataFormatterBase): @add_test_categories(["libstdcxx"]) @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc") + @override def test_with_run_command(self): - """Test that that file and class static variables display correctly.""" - self.build() - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - - lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.") - - self.runCmd("run", RUN_SUCCEEDED) - - # The stop reason of the thread should be breakpoint. - self.expect( - "thread list", - STOPPED_DUE_TO_BREAKPOINT, - substrs=["stopped", "stop reason = breakpoint"], - ) - - # This is the function to remove the custom formats in order to have a - # clean slate for the next test case. - def cleanup(): - self.runCmd("type format clear", check=False) - self.runCmd("type summary clear", check=False) - self.runCmd("type filter clear", check=False) - self.runCmd("type synth clear", check=False) - self.runCmd("settings set target.max-children-count 256", check=False) - - # Execute the cleanup function during test case tear down. - self.addTearDownHook(cleanup) - - self.runCmd("frame variable ii --show-types") - - self.runCmd( - 'type summary add -x "std::map<" --summary-string "map has ${svar%#} items" -e' - ) - - self.expect("frame variable ii", substrs=["map has 0 items", "{}"]) - - self.runCmd("c") - - self.expect( - "frame variable ii", - substrs=[ - "map has 2 items", - "[0] = ", - "first = 0", - "second = 0", - "[1] = ", - "first = 1", - "second = 1", - ], - ) - - self.runCmd("c") - - self.expect( - "frame variable ii", - substrs=[ - "map has 4 items", - "[2] = ", - "first = 2", - "second = 0", - "[3] = ", - "first = 3", - "second = 1", - ], - ) - - self.runCmd("c") - - self.expect( - "frame variable ii", - substrs=[ - "map has 9 items", - "[5] = ", - "first = 5", - "second = 0", - "[7] = ", - "first = 7", - "second = 1", - ], - ) - - self.expect( - "expression ii", - substrs=[ - "map has 9 items", - "[5] = ", - "first = 5", - "second = 0", - "[7] = ", - "first = 7", - "second = 1", - ], - ) - - # check access-by-index - self.expect("frame variable ii[0]", substrs=["first = 0", "second = 0"]) - self.expect("frame variable ii[3]", substrs=["first =", "second ="]) - - self.expect("frame variable ii[8]", matching=True, substrs=["1234567"]) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("ii").MightHaveChildren(), - "ii.MightHaveChildren() says False for non empty!", - ) - - # check that the expression parser does not make use of - # synthetic children instead of running code - # TOT clang has a fix for this, which makes the expression command here succeed - # since this would make the test fail or succeed depending on clang version in use - # this is safer commented for the time being - # self.expect("expression ii[8]", matching=False, error=True, - # substrs = ['1234567']) - - self.runCmd("c") - - self.expect("frame variable ii", substrs=["map has 0 items", "{}"]) - - self.runCmd("frame variable si --show-types") - - self.expect("frame variable si", substrs=["map has 0 items", "{}"]) - - self.runCmd("c") - - self.expect( - "frame variable si", - substrs=["map has 1 items", "[0] = ", 'first = "zero"', "second = 0"], - ) - - self.runCmd("c") - - self.expect( - "frame variable si", - substrs=[ - "map has 5 items", - '[0] = (first = "four", second = 4)', - '[1] = (first = "one", second = 1)', - '[2] = (first = "three", second = 3)', - '[3] = (first = "two", second = 2)', - '[4] = (first = "zero", second = 0)', - ], - ) - - self.expect( - "expression si", - substrs=[ - "map has 5 items", - '[0] = (first = "four", second = 4)', - '[1] = (first = "one", second = 1)', - '[2] = (first = "three", second = 3)', - '[3] = (first = "two", second = 2)', - '[4] = (first = "zero", second = 0)', - ], - ) - - # check access-by-index - self.expect("frame variable si[0]", substrs=["first = ", "four", "second = 4"]) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("si").MightHaveChildren(), - "si.MightHaveChildren() says False for non empty!", - ) - - # check that the expression parser does not make use of - # synthetic children instead of running code - # TOT clang has a fix for this, which makes the expression command here succeed - # since this would make the test fail or succeed depending on clang version in use - # this is safer commented for the time being - # self.expect("expression si[0]", matching=False, error=True, - # substrs = ['first = ', 'zero']) - - self.runCmd("c") - - self.expect("frame variable si", substrs=["map has 0 items", "{}"]) - - self.runCmd("frame variable is --show-types") - - self.expect("frame variable is", substrs=["map has 0 items", "{}"]) - - self.runCmd("c") - - self.expect( - "frame variable is", - substrs=[ - "map has 4 items", - '[0] = (first = 1, second = "is")', - '[1] = (first = 2, second = "smart")', - '[2] = (first = 3, second = "!!!")', - '[3] = (first = 85, second = "goofy")', - ], - ) - - self.expect( - "expression is", - substrs=[ - "map has 4 items", - '[0] = (first = 1, second = "is")', - '[1] = (first = 2, second = "smart")', - '[2] = (first = 3, second = "!!!")', - '[3] = (first = 85, second = "goofy")', - ], - ) - - # check access-by-index - self.expect("frame variable is[0]", substrs=["first = ", "second ="]) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("is").MightHaveChildren(), - "is.MightHaveChildren() says False for non empty!", - ) - - # check that the expression parser does not make use of - # synthetic children instead of running code - # TOT clang has a fix for this, which makes the expression command here succeed - # since this would make the test fail or succeed depending on clang version in use - # this is safer commented for the time being - # self.expect("expression is[0]", matching=False, error=True, - # substrs = ['first = ', 'goofy']) - - self.runCmd("c") - - self.expect("frame variable is", substrs=["map has 0 items", "{}"]) - - self.runCmd("frame variable ss --show-types") - - self.expect("frame variable ss", substrs=["map has 0 items", "{}"]) - - self.runCmd("c") - - self.expect( - "frame variable ss", - substrs=[ - "map has 4 items", - '[0] = (first = "a Mac..", second = "..is always a Mac!")', - '[1] = (first = "casa", second = "house")', - '[2] = (first = "ciao", second = "hello")', - '[3] = (first = "gatto", second = "cat")', - ], - ) - - self.expect( - "expression ss", - substrs=[ - "map has 4 items", - '[0] = (first = "a Mac..", second = "..is always a Mac!")', - '[1] = (first = "casa", second = "house")', - '[2] = (first = "ciao", second = "hello")', - '[3] = (first = "gatto", second = "cat")', - ], - ) - - # check access-by-index - self.expect("frame variable ss[3]", substrs=["gatto", "cat"]) - - # check that MightHaveChildren() gets it right - self.assertTrue( - self.frame().FindVariable("ss").MightHaveChildren(), - "ss.MightHaveChildren() says False for non empty!", - ) - - # check that the expression parser does not make use of - # synthetic children instead of running code - # TOT clang has a fix for this, which makes the expression command here succeed - # since this would make the test fail or succeed depending on clang version in use - # this is safer commented for the time being - # self.expect("expression ss[3]", matching=False, error=True, - # substrs = ['gatto']) - - self.runCmd("c") - - self.expect("frame variable ss", substrs=["map has 0 items", "{}"]) + self.with_run_command("a.out") diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMapWithDebug.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMapWithDebug.py new file mode 100644 index 0000000000000..1567e1e995b1f --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMapWithDebug.py @@ -0,0 +1,14 @@ +""" +Test lldb data formatter subsystem for std::map with '_GLIBCXX_DEBUG' flag +""" +from typing import override +from DataFormatterStdMap import StdMapDataFormatterBase +from lldbsuite.test.decorators import add_test_categories, expectedFailureAll + + +class StdMapDataFormatterWithDebug(StdMapDataFormatterBase): + @add_test_categories(["libstdcxx"]) + @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc") + @override + def test_with_run_command(self): + self.with_run_command("debug_a.out", "__debug::") _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits