From d09f030596ca1c4bc310a7849e34ea0e4baf70f8 Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Thu, 19 Dec 2024 22:55:50 +0100 Subject: [PATCH] templates: fix issues with spaces I have seen different scenarios regarding spaces in templates. On some platforms there might be spaces, on some others not. The biggest changes are in: src/pygccxml/parser/scanner.py -> replace spaces that are actually coming from the xml file src/pygccxml/declarations/pattern_parser.py -> remove spaces Of course all the tests had to be adjusted This "might" be a breaking change if you used to compare declarations manually, but from a pygccxml point of view all comparisons / search functions are still working as before. --- src/pygccxml/declarations/container_traits.py | 63 ++++++++-------- src/pygccxml/declarations/pattern_parser.py | 6 +- src/pygccxml/parser/scanner.py | 7 +- tests/test_call_invocation.py | 2 +- tests/test_find_container_traits.py | 36 +++++----- tests/test_remove_template_defaults.py | 72 +++++++++---------- tests/test_templates.py | 28 ++++---- tests/test_variable_matcher.py | 8 +-- tests/test_vector_traits.py | 10 ++- 9 files changed, 117 insertions(+), 115 deletions(-) diff --git a/src/pygccxml/declarations/container_traits.py b/src/pygccxml/declarations/container_traits.py index 0f8d1d61..00463e57 100644 --- a/src/pygccxml/declarations/container_traits.py +++ b/src/pygccxml/declarations/container_traits.py @@ -105,7 +105,7 @@ def erase_allocator(self, cls_name, default_allocator='std::allocator'): return value_type = c_args[0] tmpl = string.Template( - "$container< $value_type, $allocator<$value_type> >") + "$container<$value_type, $allocator<$value_type>>") tmpl = tmpl.substitute( container=c_name, value_type=value_type, @@ -122,11 +122,10 @@ def erase_container(self, cls_name, default_container_name='std::deque'): return value_type = c_args[0] dc_no_defaults = self.erase_recursive(c_args[1]) - if self.normalize(dc_no_defaults) != self.normalize( + if self.normalize(dc_no_defaults) == self.normalize( templates.join(default_container_name, [value_type])): - return - return templates.join( - c_name, [self.erase_recursive(value_type)]) + return templates.join( + c_name, [self.erase_recursive(value_type)]) def erase_container_compare( self, @@ -159,8 +158,8 @@ def erase_compare_allocator( return value_type = c_args[0] tmpl = string.Template( - "$container< $value_type, $compare<$value_type>, " + - "$allocator<$value_type> >") + "$container<$value_type, $compare<$value_type>, " + + "$allocator<$value_type>>") tmpl = tmpl.substitute( container=c_name, value_type=value_type, @@ -184,14 +183,14 @@ def erase_map_compare_allocator( mapped_type = c_args[1] tmpls = [ string.Template( - "$container< $key_type, $mapped_type, $compare<$key_type>, " + - "$allocator< std::pair< const $key_type, $mapped_type> > >"), + "$container<$key_type, $mapped_type, $compare<$key_type>, " + + "$allocator>>"), string.Template( - "$container< $key_type, $mapped_type, $compare<$key_type>, " + - "$allocator< std::pair< $key_type const, $mapped_type> > >"), + "$container<$key_type, $mapped_type, $compare<$key_type>, " + + "$allocator>>"), string.Template( - "$container< $key_type, $mapped_type, $compare<$key_type>, " + - "$allocator< std::pair< $key_type, $mapped_type> > >")] + "$container<$key_type, $mapped_type, $compare<$key_type>, " + + "$allocator>>")] for tmpl in tmpls: tmpl = tmpl.substitute( container=c_name, @@ -218,13 +217,13 @@ def erase_hash_allocator(self, cls_name): if len(c_args) == 3: default_hash = 'hash_compare' tmpl = ( - "$container< $value_type, $hash<$value_type, " + - "$less<$value_type> >, $allocator<$value_type> >") + "$container<$value_type, $hash<$value_type, " + + "$less<$value_type>>, $allocator<$value_type>>") elif len(c_args) == 4: default_hash = 'hash' tmpl = ( - "$container< $value_type, $hash<$value_type >, " + - "$equal_to<$value_type >, $allocator<$value_type> >") + "$container<$value_type, $hash<$value_type>, " + + "$equal_to<$value_type>, $allocator<$value_type>>") else: return @@ -263,14 +262,14 @@ def erase_hashmap_compare_allocator(self, cls_name): if len(c_args) == 4: default_hash = 'hash_compare' tmpl = string.Template( - "$container< $key_type, $mapped_type, " + - "$hash<$key_type, $less<$key_type> >, " + - "$allocator< std::pair< const $key_type, $mapped_type> > >") + "$container<$key_type, $mapped_type, " + + "$hash<$key_type, $less<$key_type>>, " + + "$allocator>>") if key_type.startswith('const ') or key_type.endswith(' const'): tmpl = string.Template( - "$container< $key_type, $mapped_type, $hash<$key_type, " + - "$less<$key_type> >, $allocator< std::pair< $key_type, " + - "$mapped_type> > >") + "$container<$key_type, $mapped_type, $hash<$key_type, " + + "$less<$key_type>>, $allocator>>") elif len(c_args) == 5: default_hash = 'hash' if self.unordered_maps_and_sets: @@ -279,31 +278,31 @@ def erase_hashmap_compare_allocator(self, cls_name): "$hash<$key_type>, " + "$equal_to<$key_type>, " + "$allocator > >") + "$mapped_type>>>") if key_type.startswith('const ') or \ key_type.endswith(' const'): tmpl = string.Template( "$container<$key_type, $mapped_type, " + - "$hash<$key_type >, " + - "$equal_to<$key_type >, " + + "$hash<$key_type>, " + + "$equal_to<$key_type>, " + "$allocator > >") + "$mapped_type>>>") else: tmpl = string.Template( - "$container< $key_type, $mapped_type, " + "$container<$key_type, $mapped_type, " "$hash<$key_type >, " + "$equal_to<$key_type>, " - "$allocator< $mapped_type> >") + "$allocator<$mapped_type>>") if key_type.startswith('const ') or \ key_type.endswith(' const'): # TODO: this template is the same than above. # Make sure why this was needed and if this is # tested. There may be a const missing somewhere. tmpl = string.Template( - "$container< $key_type, $mapped_type, " + - "$hash<$key_type >, " + + "$container<$key_type, $mapped_type, " + + "$hash<$key_type>, " + "$equal_to<$key_type>, " + - "$allocator< $mapped_type > >") + "$allocator<$mapped_type>>") else: return diff --git a/src/pygccxml/declarations/pattern_parser.py b/src/pygccxml/declarations/pattern_parser.py index 093e692b..da2479d9 100644 --- a/src/pygccxml/declarations/pattern_parser.py +++ b/src/pygccxml/declarations/pattern_parser.py @@ -192,11 +192,11 @@ def join(self, name, args, arg_separator=None): args = [_f for _f in args if _f] if not args: - args_str = ' ' + args_str = '' elif len(args) == 1: - args_str = ' ' + args[0] + ' ' + args_str = args[0] else: - args_str = ' ' + arg_separator.join(args) + ' ' + args_str = arg_separator.join(args) return ''.join([name, self.__begin, args_str, self.__end]) diff --git a/src/pygccxml/parser/scanner.py b/src/pygccxml/parser/scanner.py index f39dd05d..d11814d9 100644 --- a/src/pygccxml/parser/scanner.py +++ b/src/pygccxml/parser/scanner.py @@ -285,7 +285,6 @@ def members(self): return self.__members def startElement(self, name, attrs): - try: if name not in self.__readers: return @@ -656,6 +655,12 @@ def __read_class_impl(self, class_type, attrs): name = attrs.get(XML_AN_NAME, '') if '$' in name or '.' in name: name = '' + if "<" in name and " >" in name: + # Name with template. In some rare cases there + # is a space before > (and only there), so remove + # it to be consistent with the other names that + # have no space there + name = name.replace(" >", ">") if XML_AN_INCOMPLETE in attrs: decl = self.__decl_factory.create_class_declaration(name=name) else: diff --git a/tests/test_call_invocation.py b/tests/test_call_invocation.py index 9115254d..547d2090 100644 --- a/tests/test_call_invocation.py +++ b/tests/test_call_invocation.py @@ -62,7 +62,7 @@ def test_split_on_map(): def test_join_on_vector(): - assert "vector( int, std::allocator(int) )" == \ + assert "vector(int, std::allocator(int))" == \ declarations.call_invocation.join( "vector", ("int", "std::allocator(int)")) diff --git a/tests/test_find_container_traits.py b/tests/test_find_container_traits.py index dbf6fd67..23c1ac1c 100644 --- a/tests/test_find_container_traits.py +++ b/tests/test_find_container_traits.py @@ -33,7 +33,6 @@ def __cmp_traits(global_ns, typedef, expected, partial_name, key_type=None): assert declarations.find_container_traits(cls) == expected assert cls.partial_name == partial_name cls = traits.class_declaration(cls) - print("xxxx", traits, typedef) assert traits.element_type(typedef) is not None assert cls.cache.container_element_type is not None @@ -51,77 +50,78 @@ def test_find_traits(global_ns): global_ns, "v_int", declarations.vector_traits, - "vector< int >" + "vector" ) __cmp_traits( global_ns, "l_int", declarations.list_traits, - "list< int >" + "list" ) __cmp_traits( - global_ns, "d_v_int", + global_ns, + "d_v_int", declarations.deque_traits, - "deque< std::vector< int > >" + "deque>" ) __cmp_traits( global_ns, "q_int", declarations.queue_traits, - "queue< int >" + "queue" ) __cmp_traits( global_ns, "pq_int", declarations.priority_queue_traits, - "priority_queue< int >" + "priority_queue" ) __cmp_traits( global_ns, "s_v_int", declarations.set_traits, - "set< std::vector< int > >" + "set>" ) __cmp_traits( global_ns, "ms_v_int", declarations.multiset_traits, - "multiset< std::vector< int > >", + "multiset>", ) __cmp_traits( global_ns, "m_i2d", declarations.map_traits, - "map< int, double >", + "map", "int" ) __cmp_traits( global_ns, "mm_i2d", declarations.multimap_traits, - "multimap< int, double >", + "multimap", "int", ) __cmp_traits( global_ns, "hs_v_int", declarations.unordered_set_traits, - "unordered_set< std::vector< int > >", + "unordered_set>", ) __cmp_traits( global_ns, "mhs_v_int", declarations.unordered_multiset_traits, - "unordered_multiset< std::vector< int > >", + "unordered_multiset>", ) __cmp_traits( global_ns, "hm_i2d", declarations.unordered_map_traits, - "unordered_map< int, double >", + "unordered_map", "int", ) __cmp_traits( global_ns, "hmm_i2d", declarations.unordered_multimap_traits, - "unordered_multimap< int, double >", + "unordered_multimap", "int", ) @@ -129,13 +129,13 @@ def test_find_traits(global_ns): def test_multimap(global_ns): m = global_ns.class_(lambda decl: decl.name.startswith("multimap")) declarations.find_container_traits(m) - assert m.partial_name == "multimap< int, int >" + assert m.partial_name == "multimap" def test_recursive_partial_name(global_ns): f1 = global_ns.free_function("f1") t1 = declarations.class_traits.get_declaration(f1.arguments[0].decl_type) - assert "type< std::set< std::vector< int > > >" == t1.partial_name + assert "type>>" == t1.partial_name def test_remove_defaults_partial_name_namespace(global_ns): @@ -154,7 +154,7 @@ def test_from_ogre(): "map, " + "std::allocator > >" + + "(std::string&, Ogre::MaterialScriptContext&)>>>" ) ct = declarations.find_container_traits(x) ct.remove_defaults(x) diff --git a/tests/test_remove_template_defaults.py b/tests/test_remove_template_defaults.py index 5f5024a4..5fbfef5b 100644 --- a/tests/test_remove_template_defaults.py +++ b/tests/test_remove_template_defaults.py @@ -37,91 +37,91 @@ def global_ns(): def test_vector(global_ns): v_int = global_ns.typedef('v_int') v_traits = declarations.vector_traits - assert 'vector< int >' == v_traits.remove_defaults(v_int) + assert 'vector' == v_traits.remove_defaults(v_int) v_string = global_ns.typedef('v_string') - assert 'vector< std::string >' == \ + assert 'vector' == \ v_traits.remove_defaults(v_string) v_v_int = global_ns.typedef('v_v_int') - assert 'vector< std::vector< int > >' == \ + assert 'vector>' == \ v_traits.remove_defaults(v_v_int) def test_list(global_ns): l_int = global_ns.typedef('l_int') l_traits = declarations.list_traits - assert 'list< int >' == l_traits.remove_defaults(l_int) + assert 'list' == l_traits.remove_defaults(l_int) l_wstring = global_ns.typedef('l_wstring') - assert 'list< std::wstring >' == l_traits.remove_defaults(l_wstring) + assert 'list' == l_traits.remove_defaults(l_wstring) def test_deque(global_ns): d_v_int = global_ns.typedef('d_v_int') d_v_traits = declarations.deque_traits - assert 'deque< std::vector< int > >' == \ + assert 'deque>' == \ d_v_traits.remove_defaults(d_v_int) d_l_string = global_ns.typedef('d_l_string') - assert 'deque< std::list< std::string > >' == \ + assert 'deque>' == \ d_v_traits.remove_defaults(d_l_string) def test_queue(global_ns): q_int = global_ns.typedef('q_int') q_traits = declarations.queue_traits - assert 'queue< int >' == q_traits.remove_defaults(q_int) + assert 'queue' == q_traits.remove_defaults(q_int) q_string = global_ns.typedef('q_string') - assert 'queue< std::string >' == q_traits.remove_defaults(q_string) + assert 'queue' == q_traits.remove_defaults(q_string) def test_priority_queue(global_ns): pq_int = global_ns.typedef('pq_int') pq_traits = declarations.priority_queue_traits - assert 'priority_queue< int >' == pq_traits.remove_defaults(pq_int) + assert 'priority_queue' == pq_traits.remove_defaults(pq_int) pq_string = global_ns.typedef('pq_string') - assert 'priority_queue< std::string >' == \ + assert 'priority_queue' == \ pq_traits.remove_defaults(pq_string) def test_set(global_ns): s_v_int = global_ns.typedef('s_v_int') - assert 'set< std::vector< int > >' == \ + assert 'set>' == \ declarations.set_traits.remove_defaults(s_v_int) s_string = global_ns.typedef('s_string') - assert 'set< std::string >' == \ + assert 'set' == \ declarations.set_traits.remove_defaults(s_string) def test_multiset(global_ns): ms_v_int = global_ns.typedef('ms_v_int') ms_v_traits = declarations.multiset_traits - assert 'multiset< std::vector< int > >' == \ + assert 'multiset>' == \ ms_v_traits.remove_defaults(ms_v_int) ms_string = global_ns.typedef('ms_string') - assert 'multiset< std::string >' == \ + assert 'multiset' == \ ms_v_traits.remove_defaults(ms_string) def test_map(global_ns): m_i2d = global_ns.typedef('m_i2d') - assert 'map< int, double >' == \ + assert 'map' == \ declarations.map_traits.remove_defaults(m_i2d) m_wstr2d = global_ns.typedef('m_wstr2d') - assert 'map< std::wstring, double >' == \ + assert 'map' == \ declarations.map_traits.remove_defaults(m_wstr2d) m_v_i2m_wstr2d = global_ns.typedef('m_v_i2m_wstr2d') - m = 'map< const std::vector< int >, std::map< std::wstring, double > >' + m = 'map, std::map>' assert m == declarations.map_traits.remove_defaults(m_v_i2m_wstr2d) def test_multimap(global_ns): mm_i2d = global_ns.typedef('mm_i2d') mm_traits = declarations.multimap_traits - assert 'multimap< int, double >' == mm_traits.remove_defaults(mm_i2d) + assert 'multimap' == mm_traits.remove_defaults(mm_i2d) mm_wstr2d = global_ns.typedef('mm_wstr2d') - assert 'multimap< const std::wstring, double >' == \ + assert 'multimap' == \ mm_traits.remove_defaults(mm_wstr2d) mm_v_i2mm_wstr2d = global_ns.typedef('mm_v_i2mm_wstr2d') - assert ('multimap< const std::vector< int >, ' + - 'const std::multimap< const std::wstring, double > >') == \ + assert ('multimap, ' + + 'const std::multimap>') == \ mm_traits.remove_defaults(mm_v_i2mm_wstr2d) @@ -129,11 +129,11 @@ def test_hash_set(global_ns): hs_v_int = global_ns.typedef('hs_v_int') hs_traits = declarations.unordered_set_traits name = 'unordered_set' - assert (name + '< std::vector< int > >') == \ + assert (name + '>') == \ hs_traits.remove_defaults(hs_v_int), \ hs_traits.remove_defaults(hs_v_int) hs_string = global_ns.typedef('hs_string') - assert (name + '< std::string >') == \ + assert (name + '') == \ hs_traits.remove_defaults(hs_string) @@ -141,10 +141,10 @@ def test_hash_multiset(global_ns): mhs_v_int = global_ns.typedef('mhs_v_int') mhs_traits = declarations.unordered_multiset_traits name = 'unordered_multiset' - assert (name + '< std::vector< int > >') == \ + assert (name + '>') == \ mhs_traits.remove_defaults(mhs_v_int) mhs_string = global_ns.typedef('mhs_string') - assert (name + '< std::string >') == \ + assert (name + '') == \ mhs_traits.remove_defaults(mhs_string) @@ -152,10 +152,10 @@ def test_hash_map(global_ns): hm_i2d = global_ns.typedef('hm_i2d') hm_traits = declarations.unordered_map_traits name = 'unordered_map' - assert (name + '< int, double >') == \ + assert (name + '') == \ hm_traits.remove_defaults(hm_i2d) hm_wstr2d = global_ns.typedef('hm_wstr2d') - assert (name + '< std::wstring, double >') == \ + assert (name + '') == \ hm_traits.remove_defaults(hm_wstr2d) @@ -163,10 +163,10 @@ def test_hash_multimap(global_ns): hmm_i2d = global_ns.typedef('hmm_i2d') hmm_traits = declarations.unordered_multimap_traits name = 'unordered_multimap' - assert (name + '< int, double >') == \ + assert (name + '') == \ hmm_traits.remove_defaults(hmm_i2d) hmm_wstr2d = global_ns.typedef('hmm_wstr2d') - assert (name + '< const std::wstring, double >') == \ + assert (name + '') == \ hmm_traits.remove_defaults(hmm_wstr2d) hmm_v_i2mm_wstr2d = global_ns.typedef('hmm_v_i2mm_wstr2d') @@ -174,12 +174,12 @@ def test_hash_multimap(global_ns): hmm_traits_value = hmm_traits.remove_defaults(hmm_v_i2mm_wstr2d) possible_values = ( - name + '< const std::vector< int >, ' + - 'const __gnu_cxx::' + name + '< const std::wstring, double > >', - name + '< const std::vector< int >, ' + + name + ', ' + + 'const __gnu_cxx::' + name + '>', + name + ', ' + 'const std::' + utils.get_tr1(hmm_traits_value) + name + - '< const std::wstring, double > >', - name + '< const std::vector< int >, ' + - 'const stdext::' + name + '< const std::wstring, double > >') + '>', + name + ', ' + + 'const stdext::' + name + '>') assert hmm_traits_value in possible_values, hmm_traits_value diff --git a/tests/test_templates.py b/tests/test_templates.py index 25ab5ad4..738c88b9 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -21,25 +21,25 @@ def __test_is_template_impl(decl_string): def test_split_on_vector(): - __test_is_template_impl("vector >") + __test_is_template_impl("vector>") __test_split_impl( - "vector >", + "vector>", "vector", ["int", "std::allocator"]) __test_split_recursive_impl( - "vector >", + "vector>", [("vector", ["int", "std::allocator"]), ("std::allocator", ["int"])]) def test_split_on_string(): __test_is_template_impl( - "basic_string,std::allocator >") + "basic_string, std::allocator>") __test_split_impl( - "basic_string,std::allocator >", + "basic_string, std::allocator>", "basic_string", ["char", "std::char_traits", @@ -48,24 +48,24 @@ def test_split_on_string(): def test_split_on_map(): __test_is_template_impl( - "map >," + - "std::less,std::allocator > > > >") + "map>," + + "std::less, std::allocator>>>>") __test_split_impl( - "map >," + - "std::less,std::allocator > > > >", + "map>," + + "std::less, std::allocator>>>>", "map", ["long int", - "std::vector >", + "std::vector>", "std::less", "std::allocator > > >"]) + "std::vector>>>"]) def test_join_on_vector(): - assert "vector< int, std::allocator >" == \ + assert "vector>" == \ declarations.templates.join( "vector", ("int", "std::allocator")) diff --git a/tests/test_variable_matcher.py b/tests/test_variable_matcher.py index 49347f7d..d01d33cb 100644 --- a/tests/test_variable_matcher.py +++ b/tests/test_variable_matcher.py @@ -54,7 +54,7 @@ def test_no_defaults(): global_ns = declarations.get_global_namespace(decls) global_ns.decls(lambda decl: 'vector<' in decl.name) - global_ns.decl('vector< _0_ >') - global_ns.class_('vector< std::vector< int > >') - global_ns.class_('vector< std::string >') - global_ns.decl('vector< const int >') + global_ns.decl('vector<_0_>') + global_ns.class_('vector>') + global_ns.class_('vector') + global_ns.decl('vector') diff --git a/tests/test_vector_traits.py b/tests/test_vector_traits.py index 81efa62b..1e16a407 100644 --- a/tests/test_vector_traits.py +++ b/tests/test_vector_traits.py @@ -71,20 +71,18 @@ def test_no(global_ns): def test_declaration(): cnt = ( 'std::vector, ' + - 'std::allocator >,std::allocator, std::allocator > > >' + + 'std::allocator>,std::allocator, std::allocator>>>' + '@::std::vector, ' + - 'std::allocator >,std::allocator, std::allocator > > >') + 'std::allocator>, std::allocator, std::allocator>>>') traits = declarations.find_container_traits(cnt) assert declarations.vector_traits == traits def test_element_type(global_ns): do_nothing = global_ns.free_function('do_nothing') - print(do_nothing) v = declarations.remove_reference( declarations.remove_declarated( do_nothing.arguments[0].decl_type)) - print(v, type(v)) declarations.vector_traits.element_type(v)