[Lldb-commits] [lldb] 566bfbb - [formatters] Add a libstdcpp formatter for bitset and unify tests across stdlibs

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 26 14:49:57 PDT 2021


Author: Danil Stefaniuc
Date: 2021-10-26T14:49:50-07:00
New Revision: 566bfbb740bb0ffef827ce983d7aa899236fcb88

URL: https://github.com/llvm/llvm-project/commit/566bfbb740bb0ffef827ce983d7aa899236fcb88
DIFF: https://github.com/llvm/llvm-project/commit/566bfbb740bb0ffef827ce983d7aa899236fcb88.diff

LOG: [formatters] Add a libstdcpp formatter for bitset and unify tests across stdlibs

This diff adds a data formatter for libstdcpp's bitset. Besides, it unifies the tests for bitset for libcxx and libstdcpp for maintainability.

Reviewed By: wallace

Differential Revision: https://reviews.llvm.org/D112180

Added: 
    lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/Makefile
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/TestDataFormatterGenericBitset.py
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/main.cpp

Modified: 
    lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
    lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h

Removed: 
    lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/Makefile
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/TestDataFormatterLibcxxBitset.py
    lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/main.cpp


################################################################################
diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 2a541a9e528cd..eb53649ab0ff9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -3,9 +3,9 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   CPlusPlusLanguage.cpp
   CPlusPlusNameParser.cpp
   CxxStringTypes.cpp
+  GenericBitset.cpp
   LibCxx.cpp
   LibCxxAtomic.cpp
-  LibCxxBitset.cpp
   LibCxxInitializerList.cpp
   LibCxxList.cpp
   LibCxxMap.cpp

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 4ef35eefaf32f..240bbecfc2c53 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -895,6 +895,8 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   SyntheticChildren::Flags stl_synth_flags;
   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
       false);
+  SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
+  stl_deref_flags.SetFrontEndWantsDereference();
 
   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
       RegularExpression("^std::vector<.+>(( )?&)?$"),
@@ -913,6 +915,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
           "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
   stl_summary_flags.SetDontShowChildren(false);
   stl_summary_flags.SetSkipPointers(true);
+  cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
+      RegularExpression("^std::bitset<.+>(( )?&)?$"),
+      TypeSummaryImplSP(
+          new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
       RegularExpression("^std::vector<.+>(( )?&)?$"),
       TypeSummaryImplSP(
@@ -959,6 +965,12 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
       stl_synth_flags, true);
 
+  AddCXXSynthetic(
+      cpp_category_sp,
+      lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
+      "std::bitset synthetic child", ConstString("^std::bitset<.+>(( )?&)?$"),
+      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/LibCxxBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
similarity index 71%
rename from lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
rename to lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
index e5b868fc0fce0..fc8255983436c 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
@@ -1,4 +1,4 @@
-//===-- LibCxxBitset.cpp --------------------------------------------------===//
+//===-- GenericBitset.cpp //-----------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "LibCxx.h"
+#include "LibStdcpp.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/DataFormatters/FormattersHelpers.h"
 #include "lldb/Target/Target.h"
@@ -16,9 +17,15 @@ using namespace lldb_private;
 
 namespace {
 
-class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
+/// This class can be used for handling bitsets from both libcxx and libstdcpp.
+class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
 public:
-  BitsetFrontEnd(ValueObject &valobj);
+  enum class StdLib {
+    LibCxx,
+    LibStdcpp,
+  };
+
+  GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
 
   size_t GetIndexOfChildWithName(ConstString name) override {
     return formatters::ExtractIndexFromString(name.GetCString());
@@ -30,6 +37,8 @@ class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
   ValueObjectSP GetChildAtIndex(size_t idx) override;
 
 private:
+  ConstString GetDataContainerMemberName();
+
   // The lifetime of a ValueObject and all its derivative ValueObjects
   // (children, clones, etc.) is managed by a ClusterManager. These
   // objects are only destroyed when every shared pointer to any of them
@@ -38,15 +47,16 @@ class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
   // Value objects created from raw data (i.e. in a 
diff erent cluster) must
   // be referenced via shared pointer to keep them alive, however.
   std::vector<ValueObjectSP> m_elements;
-  ValueObject* m_first = nullptr;
+  ValueObject *m_first = nullptr;
   CompilerType m_bool_type;
   ByteOrder m_byte_order = eByteOrderInvalid;
   uint8_t m_byte_size = 0;
+  StdLib m_stdlib;
 };
 } // namespace
 
-BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj)
-    : SyntheticChildrenFrontEnd(valobj) {
+GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
+    : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
   m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
   if (auto target_sp = m_backend.GetTargetSP()) {
     m_byte_order = target_sp->GetArchitecture().GetByteOrder();
@@ -55,7 +65,16 @@ BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj)
   }
 }
 
-bool BitsetFrontEnd::Update() {
+ConstString GenericBitsetFrontEnd::GetDataContainerMemberName() {
+  switch (m_stdlib) {
+  case StdLib::LibCxx:
+    return ConstString("__first_");
+  case StdLib::LibStdcpp:
+    return ConstString("_M_w");
+  }
+}
+
+bool GenericBitsetFrontEnd::Update() {
   m_elements.clear();
   m_first = nullptr;
 
@@ -65,16 +84,17 @@ bool BitsetFrontEnd::Update() {
   size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay();
 
   size_t size = 0;
+
   if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
     size = arg->value.getLimitedValue(capping_size);
 
   m_elements.assign(size, ValueObjectSP());
-
-  m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true).get();
+  m_first = m_backend.GetChildMemberWithName(GetDataContainerMemberName(), true)
+                .get();
   return false;
 }
 
-ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
+ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(size_t idx) {
   if (idx >= m_elements.size() || !m_first)
     return ValueObjectSP();
 
@@ -112,9 +132,18 @@ ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
   return m_elements[idx];
 }
 
+SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
+    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+  if (valobj_sp)
+    return new GenericBitsetFrontEnd(*valobj_sp,
+                                     GenericBitsetFrontEnd::StdLib::LibStdcpp);
+  return nullptr;
+}
+
 SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
   if (valobj_sp)
-    return new BitsetFrontEnd(*valobj_sp);
+    return new GenericBitsetFrontEnd(*valobj_sp,
+                                     GenericBitsetFrontEnd::StdLib::LibCxx);
   return nullptr;
 }

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 9e41aa0ffc011..b6f9c469fedda 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -41,6 +41,10 @@ SyntheticChildrenFrontEnd *
 LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                        lldb::ValueObjectSP);
 
+SyntheticChildrenFrontEnd *
+LibStdcppBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
+                                        lldb::ValueObjectSP);
+
 SyntheticChildrenFrontEnd *
 LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                                 lldb::ValueObjectSP);

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/Makefile
similarity index 75%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/Makefile
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/Makefile
index 680e1abfbef58..99998b20bcb05 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/Makefile
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/Makefile
@@ -1,4 +1,3 @@
 CXX_SOURCES := main.cpp
 
-USE_LIBCPP := 1
 include Makefile.rules

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/TestDataFormatterGenericBitset.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/TestDataFormatterGenericBitset.py
new file mode 100644
index 0000000000000..7dac8ec06c0b8
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/TestDataFormatterGenericBitset.py
@@ -0,0 +1,93 @@
+"""
+Test lldb data formatter subsystem for bitset for libcxx and libstdcpp.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+USE_LIBSTDCPP = "USE_LIBSTDCPP"
+USE_LIBCPP = "USE_LIBCPP"
+VALUE = "VALUE"
+REFERENCE = "REFERENCE"
+POINTER = "POINTER"
+
+class GenericBitsetDataFormatterTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        TestBase.setUp(self)
+        primes = [1]*300
+        primes[0] = primes[1] = 0
+        for i in range(2, len(primes)):
+            for j in range(2*i, len(primes), i):
+                primes[j] = 0
+        self.primes = primes
+    
+    def getBitsetVariant(self, size, variant):
+        if variant == VALUE:
+            return "std::bitset<" + str(size) + ">"
+        elif variant == REFERENCE:
+            return "std::bitset<" + str(size) + "> &"
+        elif variant == POINTER:
+            return "std::bitset<" + str(size) + "> *"
+        return ""
+
+    def check(self, name, size, variant):
+        var = self.frame().FindVariable(name)
+        self.assertTrue(var.IsValid())
+        self.assertEqual(var.GetNumChildren(), size)
+        children = []
+        for i in range(size):
+            child = var.GetChildAtIndex(i)
+            children.append(ValueCheck(value=str(bool(child.GetValueAsUnsigned())).lower()))
+            self.assertEqual(child.GetValueAsUnsigned(), self.primes[i],
+                    "variable: %s, index: %d"%(name, size))
+        self.expect_var_path(name,type=self.getBitsetVariant(size,variant),children=children) 
+
+    def do_test_value(self, stdlib_type):
+        """Test that std::bitset is displayed correctly"""
+        self.build(dictionary={stdlib_type: "1"})
+
+        lldbutil.run_to_source_breakpoint(self, '// break here',
+                lldb.SBFileSpec("main.cpp", False))
+
+        self.check("empty", 0, VALUE)
+        self.check("small", 13, VALUE)
+        self.check("large", 70, VALUE)
+
+    @add_test_categories(["libstdcxx"])
+    def test_value_libstdcpp(self):
+        self.do_test_value(USE_LIBSTDCPP)
+
+    @add_test_categories(["libc++"])
+    def test_value_libcpp(self):
+        self.do_test_value(USE_LIBCPP)
+
+    def do_test_ptr_and_ref(self, stdlib_type):
+        """Test that ref and ptr to std::bitset is displayed correctly"""
+        self.build(dictionary={stdlib_type: "1"})
+
+        (_, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self,
+                'Check ref and ptr',
+                lldb.SBFileSpec("main.cpp", False))
+
+        self.check("ref", 13, REFERENCE)
+        self.check("ptr", 13, POINTER)
+
+        lldbutil.continue_to_breakpoint(process, bkpt)
+
+        self.check("ref", 70, REFERENCE)
+        self.check("ptr", 70, POINTER)
+
+    @add_test_categories(["libstdcxx"])
+    def test_ptr_and_ref_libstdcpp(self):
+        self.do_test_ptr_and_ref(USE_LIBSTDCPP)
+
+    @add_test_categories(["libc++"])
+    def test_ptr_and_ref_libcpp(self):
+        self.do_test_ptr_and_ref(USE_LIBCPP)

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/main.cpp
similarity index 67%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/main.cpp
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/main.cpp
index 2a1532adb4b29..c7be1c5c71337 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/bitset/main.cpp
@@ -1,27 +1,26 @@
 #include <bitset>
 #include <stdio.h>
 
-template<std::size_t N>
-void fill(std::bitset<N> &b) {
+template <std::size_t N> void fill(std::bitset<N> &b) {
   b.set();
   b[0] = b[1] = false;
   for (std::size_t i = 2; i < N; ++i) {
-    for (std::size_t j = 2*i; j < N; j+=i)
+    for (std::size_t j = 2 * i; j < N; j += i)
       b[j] = false;
   }
 }
 
-template<std::size_t N>
+template <std::size_t N>
 void by_ref_and_ptr(std::bitset<N> &ref, std::bitset<N> *ptr) {
-    // Check ref and ptr
-    return;
+  // Check ref and ptr
+  return;
 }
 
 int main() {
   std::bitset<0> empty;
   std::bitset<13> small;
   fill(small);
-  std::bitset<200> large;
+  std::bitset<70> large;
   fill(large);
   by_ref_and_ptr(small, &small); // break here
   by_ref_and_ptr(large, &large);

diff  --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/TestDataFormatterLibcxxBitset.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/TestDataFormatterLibcxxBitset.py
deleted file mode 100644
index 26f1972257bdd..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/bitset/TestDataFormatterLibcxxBitset.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""
-Test lldb data formatter subsystem.
-"""
-
-
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class TestDataFormatterLibcxxBitset(TestBase):
-
-    mydir = TestBase.compute_mydir(__file__)
-
-    def setUp(self):
-        TestBase.setUp(self)
-
-        primes = [1]*300
-        primes[0] = primes[1] = 0
-        for i in range(2, len(primes)):
-            for j in range(2*i, len(primes), i):
-                primes[j] = 0
-        self.primes = primes
-
-    def check(self, name, size):
-        var = self.frame().FindVariable(name)
-        self.assertTrue(var.IsValid())
-        self.assertEqual(var.GetNumChildren(), size)
-        for i in range(size):
-            child = var.GetChildAtIndex(i)
-            self.assertEqual(child.GetValueAsUnsigned(), self.primes[i],
-                    "variable: %s, index: %d"%(name, size))
-
-    @add_test_categories(["libc++"])
-    def test_value(self):
-        """Test that std::bitset is displayed correctly"""
-        self.build()
-        lldbutil.run_to_source_breakpoint(self, '// break here',
-                lldb.SBFileSpec("main.cpp", False))
-
-        self.check("empty", 0)
-        self.check("small", 13)
-        self.check("large", 200)
-
-    @add_test_categories(["libc++"])
-    def test_ptr_and_ref(self):
-        """Test that ref and ptr to std::bitset is displayed correctly"""
-        self.build()
-        (_, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self,
-                'Check ref and ptr',
-                lldb.SBFileSpec("main.cpp", False))
-
-        self.check("ref", 13)
-        self.check("ptr", 13)
-
-        lldbutil.continue_to_breakpoint(process, bkpt)
-
-        self.check("ref", 200)
-        self.check("ptr", 200)


        


More information about the lldb-commits mailing list