Skip to content

Commit 1438982

Browse files
praetorian20iMichka
authored andcommitted
Fix unqualified enums in default arguments for CastXML
CastXML currently doesn't modify enum names used in default arguments for functions, it simply uses the same text present in the source file. This causes compilation failures in bindings generated by pyplusplus in case of code such as the following: namespace ns1 { namespace ns2 { enum color { red }; void foo(color arg = ns2::red); } } In this case, CastXML produces "ns2::red" as the default value while GCCXML removes the namespace name and sets the default value to "red". pygccxml's patcher for unqualified names expects GCCXML's behavior, so it fails to detect the CastXML output as one needing further qualification. Consequently, pyplusplus refers to the default value as "ns2::red", which fails compilation because the name needs to be fully qualified as "ns1::ns2::red". This fix produces the desired qualified output from pygccxml with both GCCXML and CastXML. Change-Id: I724408981b69bc184e246636da3fac0c70cb215c Cherry-picked from the develop branch
1 parent aa54146 commit 1438982

File tree

3 files changed

+52
-35
lines changed

3 files changed

+52
-35
lines changed

pygccxml/parser/patcher.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ def __is_unqualified_enum(self, func, arg):
4444
if not declarations.is_enum(type_):
4545
return False
4646
enum_type = declarations.enum_declaration(type_)
47-
return enum_type.has_value_name(arg.default_value)
47+
# GCCXML does not qualify an enum value in the default argument
48+
# but CastXML does. Split the default value and use only the
49+
# enum value for fixing it.
50+
return enum_type.has_value_name(
51+
arg.default_value.split('::')[-1])
4852

4953
def __fix_unqualified_enum(self, func, arg):
5054
type_ = declarations.remove_reference(declarations.remove_cv(arg.type))
5155
enum_type = declarations.enum_declaration(type_)
5256
return self.__join_names(
5357
enum_type.parent.decl_string,
54-
arg.default_value)
58+
arg.default_value.split('::')[-1])
5559

5660
def __is_invalid_integral(self, func, arg):
5761
type_ = declarations.remove_reference(declarations.remove_cv(arg.type))

unittests/data/patcher.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,19 @@
1212
namespace ns1{ namespace ns2{
1313

1414
enum fruit{ apple, orange };
15+
void fix_enum2( fruit arg=apple );
1516

1617
} }
1718

1819
void fix_enum( ns1::ns2::fruit arg=ns1::ns2::apple );
1920

21+
namespace ns3{
22+
23+
using namespace ns1::ns2;
24+
void fix_enum3( fruit arg=orange );
25+
26+
}
27+
2028
typedef unsigned long long ull;
2129
void fix_numeric( ull arg=(ull)-1 );
2230

unittests/patcher_tester.py

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,82 +23,87 @@ def __init__(self, architecture, *args):
2323
def test_enum_patcher(self):
2424
fix_enum = self.global_ns.free_fun("fix_enum")
2525
default_val = fix_enum.arguments[0].default_value
26-
if "CastXML" in utils.xml_generator:
27-
# Most clean output, no need to patch
28-
self.assertTrue(default_val == "ns1::ns2::apple")
29-
else:
30-
self.assertTrue(default_val == "::ns1::ns2::apple")
26+
self.assertEqual(default_val, "::ns1::ns2::apple")
27+
28+
if 32 == self.architecture or "CastXML" in utils.xml_generator:
29+
fix_enum2 = self.global_ns.free_fun("fix_enum2")
30+
default_val = fix_enum2.arguments[0].default_value
31+
self.assertEqual(default_val, "::ns1::ns2::apple")
32+
33+
ns1 = self.global_ns.namespace("ns1")
34+
ns2 = ns1.namespace("ns2")
35+
fix_enum2 = ns2.free_fun("fix_enum2")
36+
default_val = fix_enum2.arguments[0].default_value
37+
self.assertEqual(default_val, "::ns1::ns2::apple")
38+
39+
fix_enum3 = self.global_ns.free_fun("fix_enum3")
40+
default_val = fix_enum3.arguments[0].default_value
41+
self.assertEqual(default_val, "::ns1::ns2::orange")
3142

3243
# double_call = declarations.find_declaration(
3344
# decls, type=declarations.free_function_t, name='double_call' )
3445

3546
def test_numeric_patcher(self):
36-
fix_numeric = self.global_ns.free_fun("fix_numeric")
47+
fix_numeric = self.global_ns.free_function("fix_numeric")
3748
if 32 == self.architecture:
3849
if "0.9" in utils.xml_generator:
3950
if platform.machine() == "x86_64":
40-
self.assertTrue(
41-
fix_numeric.arguments[0].default_value == "-1u",
42-
fix_numeric.arguments[0].default_value)
51+
self.assertEqual(
52+
fix_numeric.arguments[0].default_value, "-1u")
4353
else:
4454
val = "0xffffffffffffffffu"
45-
self.assertTrue(
46-
fix_numeric.arguments[0].default_value == val,
47-
fix_numeric.arguments[0].default_value)
55+
self.assertEqual(
56+
fix_numeric.arguments[0].default_value, val)
4857
else:
4958
val = "0xffffffffffffffff"
50-
self.assertTrue(
51-
fix_numeric.arguments[0].default_value == val,
52-
fix_numeric.arguments[0].default_value)
59+
self.assertEqual(
60+
fix_numeric.arguments[0].default_value, val)
5361
else:
5462
if "CastXML" in utils.xml_generator:
55-
# Most clean output, no need to patch
56-
self.assertTrue(
57-
fix_numeric.arguments[0].default_value == "(ull)-1",
58-
fix_numeric.arguments[0].default_value)
63+
self.assertEqual(
64+
fix_numeric.arguments[0].default_value, "(ull)-1")
5965
else:
60-
self.assertTrue(
61-
fix_numeric.arguments[0].default_value == "0ffffffff",
62-
fix_numeric.arguments[0].default_value)
66+
self.assertEqual(
67+
fix_numeric.arguments[0].default_value, "0ffffffff")
6368

6469
def test_unnamed_enum_patcher(self):
6570
fix_unnamed = self.global_ns.free_fun("fix_unnamed")
66-
self.assertTrue(
67-
fix_unnamed.arguments[0].default_value == "int(::fx::unnamed)")
71+
self.assertEqual(
72+
fix_unnamed.arguments[0].default_value, "int(::fx::unnamed)")
6873

6974
def test_function_call_patcher(self):
7075
fix_function_call = self.global_ns.free_fun("fix_function_call")
7176
default_val = fix_function_call.arguments[0].default_value
7277
if "CastXML" in utils.xml_generator:
7378
# Most clean output, no need to patch
7479
val = "calc(1, 2, 3)"
75-
self.assertTrue(default_val == val)
80+
self.assertEqual(default_val, val)
7681
elif "0.9" in utils.xml_generator:
7782
val = "function_call::calc(1, 2, 3)"
78-
self.assertTrue(default_val == val)
83+
self.assertEqual(default_val, val)
7984
else:
8085
val = "function_call::calc( 1, 2, 3 )"
81-
self.assertTrue(default_val == val)
86+
self.assertEqual(default_val, val)
8287

8388
def test_fundamental_patcher(self):
8489
fcall = self.global_ns.free_fun("fix_fundamental")
8590
val = "(unsigned int)(::fundamental::eggs)"
86-
self.assertTrue(
87-
fcall.arguments[0].default_value == val)
91+
self.assertEqual(
92+
fcall.arguments[0].default_value, val)
8893

8994
def test_constructor_patcher(self):
9095
typedef__func = self.global_ns.free_fun("typedef__func")
9196
default_val = typedef__func.arguments[0].default_value
9297
if "0.9" in utils.xml_generator:
9398
val = "typedef_::original_name()"
94-
self.assertTrue(default_val == val)
99+
self.assertEqual(default_val, val)
95100
elif "CastXML" in utils.xml_generator:
96101
# Most clean output, no need to patch
97102
val = "typedef_::alias()"
98-
self.assertTrue(default_val == val)
103+
self.assertEqual(default_val, val)
99104
else:
100105
val = "::typedef_::alias( )"
101-
self.assertTrue(default_val == val)
106+
self.assertEqual(default_val, val)
102107
if 32 == self.architecture:
103108
clone_tree = self.global_ns.free_fun("clone_tree")
104109
default_values = []
@@ -116,7 +121,7 @@ def test_constructor_patcher(self):
116121
"std::allocator<char> > > >((&allocator" +
117122
"<std::basic_string<char, std::char_traits<char>, " +
118123
"std::allocator<char> > >()))")]
119-
self.assertTrue(
124+
self.assertIn(
120125
clone_tree.arguments[0].default_value in default_values)
121126

122127

0 commit comments

Comments
 (0)