Skip to content

Commit 55ad033

Browse files
committed
Fix exception in is_copy_constructor() when a typedef was passed to the constructor.
See issue #27. is_copy_constructor() will now return False in this case, instead of failing.
1 parent cf692a1 commit 55ad033

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

docs/history.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ to python 3 (keeping it compatible with python 2).
1111
In Mai 2014, Michka Popoff and the Insight Software Consortium revived pygccxml
1212
by setting up a git repositery on github, hosted along with gccxml.
1313

14+
Version 1.7.2 (unreleased)
15+
--------------------------
16+
17+
1. Fix exception in is_copy_constructor() when the constructor's argument was
18+
a typedef. is_copy_constructor() will now return False instead of failing.
19+
See issue #27.
20+
1421
Version 1.7.1
1522
-------------
1623

pygccxml/declarations/calldef.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ def __str__(self):
738738
def is_copy_constructor(self):
739739
"""
740740
Returns True if described declaration is copy constructor,
741-
otherwise False
741+
otherwise False.
742742
743743
"""
744744

@@ -753,6 +753,17 @@ def is_copy_constructor(self):
753753
# We have only one argument, get it
754754
arg = args[0]
755755

756+
if not isinstance(arg.type, cpptypes.compound_t):
757+
# An argument of type declarated_t (a typedef) could be passed to
758+
# the constructor; and it could be a reference.
759+
# But in c++ you can NOT write :
760+
# "typedef class MyClass { MyClass(const MyClass & arg) {} }"
761+
# If the argument is a typedef, this is not a copy constructor.
762+
# See the hierarchy of declarated_t and coumpound_t. They both
763+
# inherit from type_t but are not related so we can discriminate
764+
# between them.
765+
return False
766+
756767
# The argument needs to be passed by reference in a copy constructor
757768
if not type_traits.is_reference(arg.type):
758769
return False
@@ -764,8 +775,14 @@ def is_copy_constructor(self):
764775
un_aliased = type_traits.remove_alias(arg.type.base)
765776
# un_aliased now refers to const_t instance
766777
if not isinstance(un_aliased.base, cpptypes.declarated_t):
778+
# We are looking for a declaration
779+
# If "class MyClass { MyClass(const int & arg) {} }" is used,
780+
# this is not copy constructor, so we return False here.
781+
# -> un_aliased.base == cpptypes.int_t (!= cpptypes.declarated_t)
767782
return False
768783

784+
# Final check: compare the parent (the class declaration for example)
785+
# with the declaration of the type passed as argument.
769786
return id(un_aliased.base.declaration) == id(self.parent)
770787

771788
@property
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014-2016 Insight Software Consortium.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// See http://www.boost.org/LICENSE_1_0.txt
4+
5+
typedef const int & myvar;
6+
7+
class test
8+
{
9+
public:
10+
// The copy constructor
11+
test(const test & t0){};
12+
13+
// A constructor
14+
test(const float & t0){};
15+
16+
// A constructor with a typedef
17+
test(myvar t0){};
18+
};
19+
20+
// An empty class; C++ will automatically create a copy constructor
21+
class test2 {};

unittests/test_copy_constructor.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright 2014-2016 Insight Software Consortium.
2+
# Distributed under the Boost Software License, Version 1.0.
3+
# See http://www.boost.org/LICENSE_1_0.txt
4+
5+
import unittest
6+
import parser_test_case
7+
8+
from pygccxml import parser
9+
from pygccxml import declarations
10+
11+
12+
class tester_t(parser_test_case.parser_test_case_t):
13+
14+
def __init__(self, *args):
15+
parser_test_case.parser_test_case_t.__init__(self, *args)
16+
self.header = "test_copy_constructor.hpp"
17+
18+
def setUp(self):
19+
decls = parser.parse([self.header], self.config)
20+
self.global_ns = declarations.get_global_namespace(decls)
21+
22+
def test(self):
23+
"""
24+
Check the is_copy_constructor method.
25+
26+
This fails when using CastXML, see issue #27.
27+
28+
"""
29+
30+
tclass = self.global_ns.class_("test")
31+
ctors = []
32+
for decl in tclass.declarations:
33+
if isinstance(decl, declarations.calldef.constructor_t):
34+
ctors.append(decl)
35+
36+
# test::test(test const & t0) [copy constructor]
37+
self.assertTrue(ctors[0].is_copy_constructor)
38+
# test::test(float const & t0) [constructor]
39+
self.assertFalse(ctors[1].is_copy_constructor)
40+
# test::test(myvar t0) [constructor]
41+
self.assertFalse(ctors[2].is_copy_constructor)
42+
43+
t2class = self.global_ns.class_("test2")
44+
ctors = []
45+
for decl in t2class.declarations:
46+
if isinstance(decl, declarations.calldef.constructor_t):
47+
ctors.append(decl)
48+
49+
# test2::test2() [constructor]
50+
self.assertFalse(ctors[0].is_copy_constructor)
51+
# test2::test2(test2 const & arg0) [copy constructor]
52+
self.assertTrue(ctors[1].is_copy_constructor)
53+
54+
55+
def create_suite():
56+
suite = unittest.TestSuite()
57+
suite.addTest(unittest.makeSuite(tester_t))
58+
return suite
59+
60+
61+
def run_suite():
62+
unittest.TextTestRunner(verbosity=2).run(create_suite())
63+
64+
if __name__ == "__main__":
65+
run_suite()

0 commit comments

Comments
 (0)