Skip to content

Commit 138ed87

Browse files
committed
Fix problem with argument without names when building declaration string (#55)
When passing an object without name to a templated function, pygcxxml was failing when building the declaration string of the function. This is now fixed by displaying no name in the generated declaration string.
1 parent 724dea8 commit 138ed87

File tree

5 files changed

+98
-7
lines changed

5 files changed

+98
-7
lines changed

pygccxml/declarations/algorithm.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,24 @@ def full_name(decl, with_defaults=True):
124124
raise RuntimeError("Unable to generate full name for None object!")
125125
if with_defaults:
126126
if not decl.cache.full_name:
127-
decl.cache.full_name = full_name_from_declaration_path(
128-
declaration_path(decl))
127+
path = declaration_path(decl)
128+
if path == [""]:
129+
# Declarations without names are allowed (for examples class
130+
# or struct instances). In this case set an empty name..
131+
decl.cache.full_name = ""
132+
else:
133+
decl.cache.full_name = full_name_from_declaration_path(path)
129134
return decl.cache.full_name
130135
else:
131136
if not decl.cache.full_partial_name:
132-
decl.cache.full_partial_name = full_name_from_declaration_path(
133-
partial_declaration_path(decl))
137+
path = partial_declaration_path(decl)
138+
if path == [""]:
139+
# Declarations without names are allowed (for examples class
140+
# or struct instances). In this case set an empty name.
141+
decl.cache.full_partial_name = ""
142+
else:
143+
decl.cache.full_partial_name = \
144+
full_name_from_declaration_path(path)
134145
return decl.cache.full_partial_name
135146

136147

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2014-2016 Insight Software Consortium.
2+
// Copyright 2004-2009 Roman Yakovenko.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// See http://www.boost.org/LICENSE_1_0.txt
5+
6+
// Demonstrate some code where a struct without name is passed to a
7+
// templated function. See bug #55
8+
9+
template <typename type>
10+
void
11+
function(type &var) {};
12+
13+
int main()
14+
{
15+
// Create foo, a struct with no name
16+
struct { } foo;
17+
function(foo);
18+
}

unittests/test_all.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import test_cpp_standards
7272
import unnamed_classes_tester
7373
import test_map_gcc5
74+
import test_argument_without_name
7475

7576
testers = [
7677
# , demangled_tester # failing right now
@@ -134,7 +135,8 @@
134135
test_copy_constructor,
135136
test_cpp_standards,
136137
unnamed_classes_tester,
137-
test_map_gcc5
138+
test_map_gcc5,
139+
test_argument_without_name
138140
]
139141

140142
if 'posix' in os.name:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright 2014-2016 Insight Software Consortium.
2+
# Copyright 2004-2009 Roman Yakovenko.
3+
# Distributed under the Boost Software License, Version 1.0.
4+
# See http://www.boost.org/LICENSE_1_0.txt
5+
6+
import unittest
7+
import parser_test_case
8+
9+
from pygccxml import parser
10+
from pygccxml import declarations
11+
12+
13+
class tester_t(parser_test_case.parser_test_case_t):
14+
15+
def __init__(self, *args):
16+
parser_test_case.parser_test_case_t.__init__(self, *args)
17+
self.header = "test_argument_without_name.hpp"
18+
self.config.cflags = "-std=c++11"
19+
20+
def test_argument_without_name(self):
21+
22+
"""
23+
Test passing an object without name to a templated function.
24+
25+
The test was failing when building the declaration string.
26+
The declaration string will be 'void (*)( & )'. If the passed
27+
object had a name the result would then be 'void (*)(Name & )'.
28+
29+
See bug #55
30+
31+
"""
32+
33+
if self.config.xml_generator == "gccxml":
34+
return
35+
36+
decls = parser.parse([self.header], self.config)
37+
global_ns = declarations.get_global_namespace(decls)
38+
39+
criteria = declarations.calldef_matcher(name="function")
40+
free_funcs = declarations.matcher.find(criteria, global_ns)
41+
for free_func in free_funcs:
42+
decl_string = free_func.create_decl_string(with_defaults=False)
43+
self.assertEqual(decl_string, "void (*)( & )")
44+
45+
46+
def create_suite():
47+
suite = unittest.TestSuite()
48+
suite.addTest(unittest.makeSuite(tester_t))
49+
return suite
50+
51+
52+
def run_suite():
53+
unittest.TextTestRunner(verbosity=2).run(create_suite())
54+
55+
if __name__ == "__main__":
56+
run_suite()

unittests/test_map_gcc5.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright 2014-2016 Insight Software Consortium.
2+
# Copyright 2004-2009 Roman Yakovenko.
23
# Distributed under the Boost Software License, Version 1.0.
34
# See http://www.boost.org/LICENSE_1_0.txt
45

@@ -35,12 +36,15 @@ def test_map_gcc5(self):
3536

3637
# This calldef is defined with gcc > 4.9 (maybe earlier, not tested)
3738
# and -std=c++11. Calling create_decl_string is failing with gcc.
38-
# With clang the calldef does not exist so the matche
39+
# With clang the calldef does not exist so the matcher
3940
# will just return an empty list, letting the test pass.
41+
# See the test_argument_without_name.py for an equivalent test,
42+
# which is not depending on the presence of the _M_clone_node
43+
# method in the stl_tree.h file.
4044
criteria = declarations.calldef_matcher(name="_M_clone_node")
4145
free_funcs = declarations.matcher.find(criteria, global_ns)
4246
for free_funcs in free_funcs:
43-
print(free_funcs.create_decl_string(with_defaults=False))
47+
free_funcs.create_decl_string(with_defaults=False)
4448

4549

4650
def create_suite():

0 commit comments

Comments
 (0)