diff mbox

Pretty printers for versioned namespace

Message ID cb8bd0b2-5cb0-ee2c-0424-cc40210005a6@gmail.com
State New
Headers show

Commit Message

François Dumont Dec. 24, 2016, 1:47 p.m. UTC
On 15/12/2016 15:57, Jonathan Wakely wrote:
>
> And we could avoid three re.match expressions with complicated regular
> expressions by creating a helper function to do the "startswith"
> checks:
>
> def is_specialization_of(type, template_name):
>    return re.match('^std::(%s)?%s<.*>$' % (vers_nsp, template_name), 
> type) is not None
>
> Then replace impl_type.startswith('std::__uniq_ptr_impl<') with
> is_specialization_of(impl_type, '__uniq_ptr_impl')
>
> And replace impl_type.startswith('std::tuple<') with
> is_specialization_of(impl_type, 'tuple')
>
> And replace nodetype.name.startswith('std::_Rb_tree_node') with
> is_specialization_of(nodetype.name, '_Rb_tree_node')
>
> That makes the code much easier to read.
>
>
I agree that hiding the version namespace will be nicer. I just hope it 
is possible. I don't think we can really dictate gdb to hide this 
namespace during the rendering. In the attached path you will see what I 
tried to do. Problem is that I am not sure that printers.py is 
intercepting rendering of all types so version namespace will stay 
visible in those cases.

I think the 2 failures that I have with this patch are reflecting this 
problem:

type = holder<std::__7::basic_string<unsigned char, 
std::__7::char_traits<unsigned char>, std::__7::allocator<unsigned char> > >
got: type = holder<std::__7::basic_string<unsigned char, 
std::__7::char_traits<unsigned char>, std::__7::allocator<unsigned char> > >
FAIL: libstdc++-prettyprinters/whatis.cc whatis ustring_holder
type = holder<std::__7::basic_string<signed char, 
std::__7::char_traits<signed char>, std::__7::allocator<signed char> > >
got: type = holder<std::__7::basic_string<signed char, 
std::__7::char_traits<signed char>, std::__7::allocator<signed char> > >
FAIL: libstdc++-prettyprinters/whatis.cc whatis sstring_holder

Shall I simply use regex in those cases and adopt this approach ?

François
diff mbox

Patch

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 86de1ca..55bdee9 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -36,6 +36,8 @@  import sys
 # We probably can't do much about this until this GDB PR is addressed:
 # <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
 
+vers_nsp = '__7::'
+
 if sys.version_info[0] > 2:
     ### Python 3 stuff
     Iterator = object
@@ -100,11 +102,15 @@  def find_type(orig, name):
             raise ValueError("Cannot find type %s::%s" % (str(orig), name))
         typ = field.type
 
+# Test if a type is a given template instantiation.
+def is_specialization_of(type, template_name):
+   return re.match('^std::(%s)?%s<.*>$' % (vers_nsp, template_name), type) is not None
+
 class SharedPointerPrinter:
     "Print a shared_ptr or weak_ptr"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def to_string (self):
@@ -127,9 +133,9 @@  class UniquePointerPrinter:
 
     def to_string (self):
         impl_type = self.val.type.fields()[0].type.tag
-        if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
+        if is_specialization_of(impl_type, '__uniq_ptr_impl'): # New implementation
             v = self.val['_M_t']['_M_t']['_M_head_impl']
-        elif impl_type.startswith('std::tuple<'):
+        elif is_specialization_of(impl_type, 'tuple'):
             v = self.val['_M_t']['_M_head_impl']
         else:
             raise ValueError("Unsupported implementation for unique_ptr: %s" % self.val.type.fields()[0].type.tag)
@@ -179,7 +185,7 @@  class StdListPrinter:
             return ('[%d]' % count, val)
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def children(self):
@@ -299,7 +305,7 @@  class StdVectorPrinter:
                 return ('[%d]' % count, elt)
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
         self.is_bool = val.type.template_argument(0).code  == gdb.TYPE_CODE_BOOL
 
@@ -403,7 +409,7 @@  class StdTuplePrinter:
                 return ('[%d]' % self.count, impl['_M_head_impl'])
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val;
 
     def children (self):
@@ -418,7 +424,7 @@  class StdStackOrQueuePrinter:
     "Print a std::stack or std::queue"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.visualizer = gdb.default_visualizer(val['c'])
 
     def children (self):
@@ -496,7 +502,10 @@  class StdRbtreeIteratorPrinter:
     def __init__ (self, typename, val):
         self.val = val
         valtype = self.val.type.template_argument(0).strip_typedefs()
-        nodetype = gdb.lookup_type('std::_Rb_tree_node<' + str(valtype) + '>')
+        if typename.startswith('std::' + vers_nsp):
+            nodetype = gdb.lookup_type('std::' + vers_nsp + '_Rb_tree_node<' + str(valtype) + '>')
+        else:
+            nodetype = gdb.lookup_type('std::_Rb_tree_node<' + str(valtype) + '>')
         self.link_type = nodetype.strip_typedefs().pointer()
 
     def to_string (self):
@@ -552,7 +561,7 @@  class StdMapPrinter:
             return result
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def to_string (self):
@@ -592,7 +601,7 @@  class StdSetPrinter:
             return result
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def to_string (self):
@@ -609,7 +618,7 @@  class StdBitsetPrinter:
     "Print a std::bitset"
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def to_string (self):
@@ -679,7 +688,7 @@  class StdDequePrinter:
             return result
 
     def __init__(self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
         self.elttype = val.type.template_argument(0)
         size = self.elttype.sizeof
@@ -805,7 +814,7 @@  class Tr1UnorderedSetPrinter:
     "Print a tr1::unordered_set"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def hashtable (self):
@@ -831,7 +840,7 @@  class Tr1UnorderedMapPrinter:
     "Print a tr1::unordered_map"
 
     def __init__ (self, typename, val):
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
         self.val = val
 
     def hashtable (self):
@@ -897,7 +906,7 @@  class StdForwardListPrinter:
 
     def __init__(self, typename, val):
         self.val = val
-        self.typename = typename
+        self.typename = typename.replace(vers_nsp, '')
 
     def children(self):
         nodetype = find_type(self.val.type, '_Node')
@@ -952,12 +961,11 @@  class SingleObjContainerPrinter(object):
             return self.visualizer.display_hint ()
         return self.hint
 
-
 class StdExpAnyPrinter(SingleObjContainerPrinter):
     "Print a std::any or std::experimental::any"
 
     def __init__ (self, typename, val):
-        self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', typename, 1)
+        self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', typename, 1).replace(vers_nsp, '')
         self.val = val
         self.contained_type = None
         contained_value = None
@@ -972,8 +980,11 @@  class StdExpAnyPrinter(SingleObjContainerPrinter):
             if not m:
                 raise ValueError("Unknown manager function in %s" % self.typename)
 
+            mgrname = m.group(1)
             # FIXME need to expand 'std::string' so that gdb.lookup_type works
-            mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
+            if 'std::string' in mgrname:
+                mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
+
             mgrtype = gdb.lookup_type(mgrname)
             self.contained_type = mgrtype.template_argument(0)
             valptr = None
@@ -994,14 +1005,14 @@  class StdExpAnyPrinter(SingleObjContainerPrinter):
         if hasattr (self.visualizer, 'children'):
             return desc + self.visualizer.to_string ()
         valtype = self._recognize (self.contained_type)
-        return desc + valtype
+        return desc + str(valtype).replace(vers_nsp, '')
 
 class StdExpOptionalPrinter(SingleObjContainerPrinter):
     "Print a std::optional or std::experimental::optional"
 
     def __init__ (self, typename, val):
         valtype = self._recognize (val.type.template_argument(0))
-        self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1)
+        self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1).replace(vers_nsp, '')
         self.val = val
         contained_value = val['_M_payload'] if self.val['_M_engaged'] else None
         visualizer = gdb.default_visualizer (val['_M_payload'])
@@ -1021,6 +1032,7 @@  class StdVariantPrinter(SingleObjContainerPrinter):
     def __init__(self, typename, val):
         alternatives = self._template_args(val)
         self.typename = "%s<%s>" % (typename, ', '.join([self._recognize(alt) for alt in alternatives]))
+        self.typename = self.typename.replace(vers_nsp, '')
         self.index = val['_M_index']
         if self.index >= len(alternatives):
             self.contained_type = None
@@ -1058,7 +1070,7 @@  class StdNodeHandlePrinter(SingleObjContainerPrinter):
     def __init__(self, typename, val):
         self.value_type = val.type.template_argument(1)
         nodetype = val.type.template_argument(2).template_argument(0)
-        self.is_rb_tree_node = nodetype.name.startswith('std::_Rb_tree_node')
+        self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node')
         self.is_map_node = val.type.template_argument(0) != self.value_type
         nodeptr = val['_M_ptr']
         if nodeptr:
@@ -1202,7 +1214,7 @@  class Printer(object):
     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
     def add_version(self, base, name, function):
         self.add(base + name, function)
-        self.add(base + '__7::' + name, function)
+        self.add(base + vers_nsp + name, function)
 
     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
     def add_container(self, base, name, function):
@@ -1322,7 +1334,7 @@  class FilteringTypePrinter(object):
                 except:
                     pass
             if self.type_obj == type_obj:
-                return self.name
+                return self.name.replace(vers_nsp, '')
             return None
 
     def instantiate(self):
@@ -1331,6 +1343,8 @@  class FilteringTypePrinter(object):
 def add_one_type_printer(obj, match, name):
     printer = FilteringTypePrinter(match, 'std::' + name)
     gdb.types.register_type_printer(obj, printer)
+    printer = FilteringTypePrinter(match, 'std::' + vers_nsp + name)
+    gdb.types.register_type_printer(obj, printer)
 
 def register_type_printers(obj):
     global _use_type_printing
@@ -1374,7 +1388,6 @@  def register_type_printers(obj):
     add_one_type_printer(obj, 'fpos', 'streampos')
     add_one_type_printer(obj, 'basic_string', 'u16string')
     add_one_type_printer(obj, 'basic_string', 'u32string')
-
     add_one_type_printer(obj, 'basic_string_view', 'u16string_view')
     add_one_type_printer(obj, 'basic_string_view', 'u32string_view')
 
@@ -1392,46 +1405,47 @@  def register_type_printers(obj):
     add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
     add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
 
-    # Do not show defaulted template arguments in class templates
-    add_one_template_type_printer(obj, 'unique_ptr<T>',
-            'unique_ptr<(.*), std::default_delete<\\1 ?> >',
+    for vers in ('', vers_nsp):
+        # Do not show defaulted template arguments in class templates
+        add_one_template_type_printer(obj, 'unique_ptr<T>',
+            '{0}unique_ptr<(.*), std::{0}default_delete<\\1 ?> >'.format(vers),
             'unique_ptr<{1}>')
 
-    add_one_template_type_printer(obj, 'deque<T>',
-            'deque<(.*), std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'deque<T>',
+            '{0}deque<(.*), std::{0}allocator<\\1 ?> >'.format(vers),
             'deque<{1}>')
-    add_one_template_type_printer(obj, 'forward_list<T>',
-            'forward_list<(.*), std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'forward_list<T>',
+            '{0}forward_list<(.*), std::{0}allocator<\\1 ?> >'.format(vers),
             'forward_list<{1}>')
-    add_one_template_type_printer(obj, 'list<T>',
-            'list<(.*), std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'list<T>',
+            '{0}list<(.*), std::{0}allocator<\\1 ?> >'.format(vers),
             'list<{1}>')
-    add_one_template_type_printer(obj, 'vector<T>',
-            'vector<(.*), std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'vector<T>',
+            '{0}vector<(.*), std::{0}allocator<\\1 ?> >'.format(vers),
             'vector<{1}>')
-    add_one_template_type_printer(obj, 'map<Key, T>',
-            'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        add_one_template_type_printer(obj, 'map<Key, T>',
+            '{0}map<(.*), (.*), std::{0}less<\\1 ?>, std::{0}allocator<std::{0}pair<\\1 const, \\2 ?> > >'.format(vers),
             'map<{1}, {2}>')
-    add_one_template_type_printer(obj, 'multimap<Key, T>',
-            'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        add_one_template_type_printer(obj, 'multimap<Key, T>',
+            '{0}multimap<(.*), (.*), std::{0}less<\\1 ?>, std::{0}allocator<std::{0}pair<\\1 const, \\2 ?> > >'.format(vers),
             'multimap<{1}, {2}>')
-    add_one_template_type_printer(obj, 'set<T>',
-            'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'set<T>',
+            '{0}set<(.*), std::{0}less<\\1 ?>, std::{0}allocator<\\1 ?> >'.format(vers),
             'set<{1}>')
-    add_one_template_type_printer(obj, 'multiset<T>',
-            'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'multiset<T>',
+            '{0}multiset<(.*), std::{0}less<\\1 ?>, std::{0}allocator<\\1 ?> >'.format(vers),
             'multiset<{1}>')
-    add_one_template_type_printer(obj, 'unordered_map<Key, T>',
-            'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        add_one_template_type_printer(obj, 'unordered_map<Key, T>',
+            '{0}unordered_map<(.*), (.*), std::{0}hash<\\1 ?>, std::{0}equal_to<\\1 ?>, std::{0}allocator<std::{0}pair<\\1 const, \\2 ?> > >'.format(vers),
             'unordered_map<{1}, {2}>')
-    add_one_template_type_printer(obj, 'unordered_multimap<Key, T>',
-            'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+        add_one_template_type_printer(obj, 'unordered_multimap<Key, T>',
+            '{0}unordered_multimap<(.*), (.*), std::{0}hash<\\1 ?>, std::{0}equal_to<\\1 ?>, std::{0}allocator<std::{0}pair<\\1 const, \\2 ?> > >'.format(vers),
             'unordered_multimap<{1}, {2}>')
-    add_one_template_type_printer(obj, 'unordered_set<T>',
-            'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'unordered_set<T>',
+            '{0}unordered_set<(.*), std::{0}hash<\\1 ?>, std::{0}equal_to<\\1 ?>, std::{0}allocator<\\1 ?> >'.format(vers),
             'unordered_set<{1}>')
-    add_one_template_type_printer(obj, 'unordered_multiset<T>',
-            'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+        add_one_template_type_printer(obj, 'unordered_multiset<T>',
+            '{0}unordered_multiset<(.*), std::{0}hash<\\1 ?>, std::{0}equal_to<\\1 ?>, std::{0}allocator<\\1 ?> >'.format(vers),
             'unordered_multiset<{1}>')
 
     # strip the "fundamentals_v1" inline namespace from these types
@@ -1466,7 +1480,7 @@  def build_libstdcxx_dictionary ():
     libstdcxx_printer = Printer("libstdc++-v6")
 
     # For _GLIBCXX_BEGIN_NAMESPACE_VERSION.
-    vers = '(__7::)?'
+    vers = '(' + vers_nsp + ')?'
     # For _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
     container = '(__cxx1998::' + vers + ')?'
 
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
index 1c9bf3a..ae576d8 100644
--- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -148,7 +148,7 @@  class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::array<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -265,7 +265,7 @@  class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::deque<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -309,7 +309,7 @@  class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::forward_list<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -390,7 +390,7 @@  class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::(__cxx11::)?list<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -505,7 +505,7 @@  class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::vector<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -554,7 +554,7 @@  class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::%s<.*>$' % self._name, class_type.tag):
+        if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled:
@@ -586,9 +586,9 @@  class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
 
     def __call__(self, obj):
         impl_type = obj.dereference().type.fields()[0].type.tag
-        if impl_type.startswith('std::__uniq_ptr_impl<'): # New implementation
+        if re.match('^std::(__\d+::)?__uniq_ptr_impl<.*>$', impl_type): # New implementation
             return obj['_M_t']['_M_t']['_M_head_impl']
-        elif impl_type.startswith('std::tuple<'):
+        elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
             return obj['_M_t']['_M_head_impl']
         return None
 
@@ -640,7 +640,7 @@  class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
         self.methods = [self._method_dict[m] for m in self._method_dict]
 
     def match(self, class_type, method_name):
-        if not re.match('^std::unique_ptr<.*>$', class_type.tag):
+        if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
             return None
         method = self._method_dict.get(method_name)
         if method is None or not method.enabled: