Skip to content

Commit 9df1a42

Browse files
praetorian20iMichka
authored andcommitted
Fix for typedef'd unnamed class/struct
Unlike GCCXML, CastXML creates two distinct XML nodes for a typedef of the form typedef (class|struct) {} foo; The first XML node is an unnamed class/struct and the second is a typedef that refers to the first node. This requires special handling during parsing so that the name of the typedef is propagated to the class/struct. Change-Id: I91cc3753d50d41ff92c945a7b9801a0108163e6a Cherry-picked from the develop branch
1 parent 5e7ed8f commit 9df1a42

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

pygccxml/declarations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .scopedef import scopedef_t
1919
from .enumeration import enumeration_t
2020
from .namespace import namespace_t
21+
from .typedef import typedef_t
2122

2223
from .class_declaration import class_t
2324
from .class_declaration import CLASS_TYPES

pygccxml/parser/scanner.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ def startElement(self, name, attrs):
221221
self.__read_location(obj, attrs)
222222
if isinstance(obj, declarations.class_t):
223223
self.__read_bases(obj, attrs)
224+
if isinstance(obj, declarations.typedef_t):
225+
self.__update_unnamed_class(obj, attrs)
224226
self.__read_artificial(obj, attrs)
225227
self.__read_mangled(obj, attrs)
226228
self.__read_demangled(obj, attrs)
@@ -629,3 +631,36 @@ def __read_version(self, attrs):
629631
# compatibility.
630632
logger.debug('CASTXML version - None ( %s )', version_str)
631633
utils.xml_generator = declarations.xml_generators.CASTXML_None
634+
635+
def __update_unnamed_class(self, decl, attrs):
636+
"""
637+
Called for typedef declarations. If CastXML is being used, then type
638+
definitions with an unnamed class/struct are split across two nodes in
639+
the XML tree. For example,
640+
641+
typedef struct {} cls;
642+
643+
produces
644+
645+
<Struct id="_7" name="" context="_1" .../>
646+
<Typedef id="_8" name="cls" type="_7" context="_1" .../>
647+
648+
So we'll walk the list of read declarations and try to update an
649+
unnamed class/struct with matching attributes
650+
"""
651+
if 'CastXML' not in utils.xml_generator:
652+
return
653+
654+
parent = attrs.get(XML_AN_CONTEXT)
655+
if not parent:
656+
return
657+
if parent not in self.__members:
658+
return
659+
type_ = attrs.get(XML_AN_TYPE)
660+
if not type_ or type_ not in self.__declarations:
661+
return
662+
663+
referent = self.__declarations[type_]
664+
if referent.name or not isinstance(referent, declarations.class_t):
665+
return
666+
referent.name = decl.name

unittests/data/classes.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@
77
#define __classes_hpp__
88

99
struct cls{};
10+
typedef struct {} cls2;
11+
typedef class {
12+
int i;
13+
} cls3;
1014

1115
namespace ns{
1216

1317
struct nested_cls{};
18+
typedef class {} nested_cls2;
19+
typedef struct nested_cls3 {} nested_cls3;
1420

1521
}
1622

unittests/declaration_matcher_tester.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from pygccxml import parser
1010
from pygccxml import declarations
11+
from pygccxml import utils
1112

1213

1314
class tester_t(parser_test_case.parser_test_case_t):
@@ -31,6 +32,19 @@ def test_global(self):
3132
gns.class_('cls')
3233
gns.class_('::cls')
3334

35+
def test_typedefs(self):
36+
gns = self.global_ns
37+
gns.class_('cls2')
38+
if self.config.xml_generator == "castxml":
39+
gns.typedef('cls2')
40+
gns.class_('::cls2')
41+
42+
gns.class_('cls3')
43+
if self.config.xml_generator == "castxml":
44+
gns.typedef('cls3')
45+
cls3 = gns.class_('::cls3')
46+
cls3.variable('i')
47+
3448
def test_ns1(self):
3549
gns = self.global_ns
3650
ns1 = gns.namespace('ns')
@@ -43,6 +57,14 @@ def test_ns1(self):
4357
ns1.class_('nested_cls')
4458
ns1.class_('::ns::nested_cls')
4559

60+
gns.class_('nested_cls2')
61+
self.assertRaises(Exception, lambda: gns.class_('ns::nested_cls2'))
62+
gns.class_('::ns::nested_cls2')
63+
64+
gns.class_('nested_cls3')
65+
self.assertRaises(Exception, lambda: gns.class_('ns::nested_cls3'))
66+
gns.class_('::ns::nested_cls3')
67+
4668

4769
def create_suite():
4870
suite = unittest.TestSuite()

0 commit comments

Comments
 (0)