-
Notifications
You must be signed in to change notification settings - Fork 50
Fixes for cv-qualified arrays #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -284,19 +284,46 @@ def remove_reference(type): | |
def is_const(type): | ||
"""returns True, if type represents C++ const type, False otherwise""" | ||
nake_type = remove_alias(type) | ||
return isinstance(nake_type, cpptypes.const_t) | ||
if isinstance(nake_type, cpptypes.const_t): | ||
return True | ||
elif isinstance(nake_type, cpptypes.volatile_t): | ||
return is_const(nake_type.base) | ||
elif isinstance(nake_type, cpptypes.array_t): | ||
return is_const(nake_type.base) | ||
return False | ||
|
||
|
||
def remove_const(type): | ||
def remove_const(type_): | ||
"""removes const from the type definition | ||
|
||
If type is not const type, it will be returned as is | ||
""" | ||
|
||
nake_type = remove_alias(type) | ||
nake_type = remove_alias(type_) | ||
if not is_const(nake_type): | ||
return type | ||
return type_ | ||
else: | ||
# Handling for const and volatile qualified types. There is a | ||
# difference in behavior between GCCXML and CastXML for cv-qual arrays. | ||
# GCCXML produces the following nesting of types: | ||
# -> volatile_t(const_t(array_t)) | ||
# while CastXML produces the following nesting: | ||
# -> array_t(volatile_t(const_t)) | ||
# For both cases, we must unwrap the types, remove const_t, and add | ||
# back the outer layers | ||
if isinstance(nake_type, cpptypes.array_t): | ||
is_v = is_volatile(nake_type) | ||
if is_v: | ||
result_type = nake_type.base.base.base | ||
else: | ||
result_type = nake_type.base.base | ||
if is_v: | ||
result_type = cpptypes.volatile_t(result_type) | ||
return cpptypes.array_t(result_type, nake_type.size) | ||
|
||
elif isinstance(nake_type, cpptypes.volatile_t): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return cpptypes.volatile_t(nake_type.base.base) | ||
|
||
return nake_type.base | ||
|
||
|
||
|
@@ -322,7 +349,13 @@ def is_same(type1, type2): | |
def is_volatile(type): | ||
"""returns True, if type represents C++ volatile type, False otherwise""" | ||
nake_type = remove_alias(type) | ||
return isinstance(nake_type, cpptypes.volatile_t) | ||
if isinstance(nake_type, cpptypes.volatile_t): | ||
return True | ||
elif isinstance(nake_type, cpptypes.const_t): | ||
return is_volatile(nake_type.base) | ||
elif isinstance(nake_type, cpptypes.array_t): | ||
return is_volatile(nake_type.base) | ||
return False | ||
|
||
|
||
def remove_volatile(type): | ||
|
@@ -334,6 +367,16 @@ def remove_volatile(type): | |
if not is_volatile(nake_type): | ||
return type | ||
else: | ||
if isinstance(nake_type, cpptypes.array_t): | ||
is_c = is_const(nake_type) | ||
if is_c: | ||
base_type = nake_type.base.base.base | ||
else: | ||
base_type = nake_type.base.base | ||
result_type = base_type | ||
if is_c: | ||
result_type = cpptypes.const_t(result_type) | ||
return cpptypes.array_t(result_type, nake_type.size) | ||
return nake_type.base | ||
|
||
|
||
|
@@ -344,12 +387,12 @@ def remove_cv(type): | |
if not is_const(nake_type) and not is_volatile(nake_type): | ||
return type | ||
result = nake_type | ||
if is_const(nake_type): | ||
result = nake_type.base | ||
if is_const(result): | ||
result = remove_const(result) | ||
if is_volatile(result): | ||
result = result.base | ||
result = remove_volatile(result) | ||
if is_const(result): | ||
result = result.base | ||
result = remove_const(result) | ||
return result | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,65 @@ def test4(self): | |
'::xyz[2][3]' == aaaa_type.decl_string, | ||
aaaa_type.decl_string) | ||
|
||
def test5(self): | ||
code = 'char const arr[4] = {};' | ||
src_reader = parser.source_reader_t(self.config) | ||
global_ns = declarations.get_global_namespace( | ||
src_reader.read_string(code)) | ||
arr_type = global_ns.variable('arr').decl_type | ||
if self.config.xml_generator == "gccxml": | ||
self.assertTrue( | ||
'char[4] const' == arr_type.decl_string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to you that gccxml is putting the cv-qualifiers on the right of the array declarator in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No it doesn't make sense. I guess this is a gccxml bug. From what I know, the gccxml project did a lot of work to produce the xml file, and the output was not always very "clean". This may also be due to how it interacted with gcc. With castxml, we rely on the AST produced by clang/llvm. And this AST is much more robust, as far I have seen. The ordering in the xml file is always correct (there were other cases were the output was nicer when I added support for CastXML). So just leave the tests like this. It just makes sure the results stay the same in the future. CastXML will be the default xml parser in release 1.8.0, and gccxml support will be dropped in further releases, so these gccxml specific checks will be dropped anyway. |
||
arr_type.decl_string) | ||
else: | ||
self.assertTrue( | ||
'char const[4]' == arr_type.decl_string, | ||
arr_type.decl_string) | ||
self.assertTrue( | ||
declarations.is_array(arr_type)) | ||
self.assertTrue( | ||
declarations.is_const(arr_type)) | ||
|
||
def test6(self): | ||
code = 'char volatile arr[4] = {};' | ||
src_reader = parser.source_reader_t(self.config) | ||
global_ns = declarations.get_global_namespace( | ||
src_reader.read_string(code)) | ||
arr_type = global_ns.variable('arr').decl_type | ||
if self.config.xml_generator == "gccxml": | ||
self.assertTrue( | ||
'char[4] volatile' == arr_type.decl_string, | ||
arr_type.decl_string) | ||
else: | ||
self.assertTrue( | ||
'char volatile[4]' == arr_type.decl_string, | ||
arr_type.decl_string) | ||
self.assertTrue( | ||
declarations.is_array(arr_type)) | ||
self.assertTrue( | ||
declarations.is_volatile(arr_type)) | ||
|
||
def test7(self): | ||
code = 'char const volatile arr[4] = {};' | ||
src_reader = parser.source_reader_t(self.config) | ||
global_ns = declarations.get_global_namespace( | ||
src_reader.read_string(code)) | ||
arr_type = global_ns.variable('arr').decl_type | ||
if self.config.xml_generator == "gccxml": | ||
self.assertTrue( | ||
'char[4] const volatile' == arr_type.decl_string, | ||
arr_type.decl_string) | ||
else: | ||
self.assertTrue( | ||
'char const volatile[4]' == arr_type.decl_string, | ||
arr_type.decl_string) | ||
self.assertTrue( | ||
declarations.is_array(arr_type)) | ||
self.assertTrue( | ||
declarations.is_const(arr_type)) | ||
self.assertTrue( | ||
declarations.is_volatile(arr_type)) | ||
|
||
|
||
def create_suite(): | ||
suite = unittest.TestSuite() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
typedef BASE volatile NAME##_volatile_t; \ | ||
typedef BASE const volatile NAME##_const_volatile_t; | ||
|
||
|
||
struct some_struct_t{ | ||
void do_smth(); | ||
int member; | ||
|
@@ -47,9 +48,7 @@ struct incomplete_type; | |
|
||
namespace is_void{ | ||
namespace yes{ | ||
typedef void void_t; | ||
typedef void const void_cont_t; | ||
typedef void volatile void_volatile_t; | ||
TYPE_PERMUTATION( void, void ) | ||
} | ||
namespace no{ | ||
typedef void* void_ptr_t; | ||
|
@@ -186,7 +185,6 @@ namespace yes{ | |
typedef detail::dd_t dd_t; | ||
typedef detail::f_t f_t; | ||
typedef detail::g_t g_t; | ||
|
||
typedef detail::const_container const_container_t; | ||
typedef detail::const_item const_item_t; | ||
|
||
|
@@ -287,11 +285,6 @@ namespace no{ | |
namespace is_fundamental{ | ||
namespace yes{ | ||
|
||
#define FUNDAMENTAL_TYPE_PERMUTATION( BASE, NAME ) \ | ||
typedef BASE NAME##_t; \ | ||
typedef BASE const NAME##_const_t; \ | ||
typedef BASE volatile NAME##_volatile_t; | ||
|
||
TYPE_PERMUTATION( void, void ) | ||
TYPE_PERMUTATION( bool, bool ) | ||
TYPE_PERMUTATION( char, char ) | ||
|
@@ -409,7 +402,8 @@ namespace yes{ | |
typedef const void const_void_t; | ||
typedef const incomplete_type const_incomplete_type_t; | ||
typedef int* const int_const_t; | ||
//TODO typedef const int& const_int_ref_t; | ||
typedef int* volatile const int_volatile_const_t; | ||
typedef int* const volatile int_const_volatile_t; | ||
} | ||
|
||
namespace no{ | ||
|
@@ -421,32 +415,53 @@ namespace no{ | |
typedef void(*function_t)(); | ||
typedef void (some_struct_t::*member_function_t)(); | ||
typedef int int_t; | ||
typedef const int& const_int_ref_t; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved this from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. I already stumbled on this test case, and had the same reflection, but did not dig further. Looking at the git history, the +1 on that change |
||
} } | ||
|
||
namespace remove_const{ | ||
namespace before{ | ||
|
||
typedef const void x1; | ||
typedef const incomplete_type x2; | ||
typedef int* const x3; | ||
typedef int* volatile x4; | ||
typedef void const * x5; | ||
typedef int volatile const x6; | ||
typedef int const volatile x7; | ||
|
||
typedef char arr_42[42]; | ||
typedef char const arr_c_42[42]; | ||
typedef char volatile arr_v_42[42]; | ||
typedef char const volatile arr_cv_42[42]; | ||
typedef char volatile const arr_vc_42[42]; | ||
} | ||
|
||
namespace after{ | ||
typedef void x1; | ||
typedef incomplete_type x2; | ||
typedef int* x3; | ||
typedef int* volatile x4; | ||
typedef void const * x5; | ||
typedef int volatile x6; | ||
typedef int volatile x7; | ||
|
||
typedef char arr_42[42]; | ||
typedef char arr_c_42[42]; | ||
typedef char volatile arr_v_42[42]; | ||
typedef char volatile arr_cv_42[42]; | ||
typedef char volatile arr_vc_42[42]; | ||
} } | ||
|
||
namespace is_volatile{ | ||
namespace yes{ | ||
|
||
typedef void * volatile vvoid_ptr_t; | ||
typedef volatile int volatile_int_t; | ||
typedef int* volatile const int_volatile_const_t; | ||
typedef int* const volatile int_const_volatile_t; | ||
} | ||
|
||
namespace no{ | ||
typedef void volatile * void_ptr_to_v_t; | ||
typedef int* int_ptr_t; | ||
typedef const int* const_int_ptr_t; | ||
typedef int* volatile_int_ptr_t; | ||
|
@@ -463,12 +478,30 @@ namespace before{ | |
typedef void * volatile x1; | ||
typedef volatile int x2; | ||
typedef int* x3; | ||
typedef void volatile * x4; | ||
typedef int volatile const x5; | ||
typedef int const volatile x6; | ||
|
||
typedef char arr_42[42]; | ||
typedef char const arr_c_42[42]; | ||
typedef char volatile arr_v_42[42]; | ||
typedef char const volatile arr_cv_42[42]; | ||
typedef char volatile const arr_vc_42[42]; | ||
} | ||
|
||
namespace after{ | ||
typedef void * x1; | ||
typedef int x2; | ||
typedef int* x3; | ||
typedef void volatile * x4; | ||
typedef int const x5; | ||
typedef int const x6; | ||
|
||
typedef char arr_42[42]; | ||
typedef char const arr_c_42[42]; | ||
typedef char arr_v_42[42]; | ||
typedef char const arr_cv_42[42]; | ||
typedef char const arr_vc_42[42]; | ||
} } | ||
|
||
|
||
|
@@ -488,6 +521,12 @@ namespace before{ | |
typedef int* const x32; | ||
|
||
typedef void(*x40)(); | ||
|
||
typedef char arr_42[42]; | ||
typedef char const arr_c_42[42]; | ||
typedef char volatile arr_v_42[42]; | ||
typedef char const volatile arr_cv_42[42]; | ||
typedef char volatile const arr_vc_42[42]; | ||
} | ||
|
||
namespace after{ | ||
|
@@ -504,6 +543,12 @@ namespace after{ | |
typedef int* x32; | ||
|
||
typedef void(*x40)(); | ||
|
||
typedef char arr_42[42]; | ||
typedef char arr_c_42[42]; | ||
typedef char arr_v_42[42]; | ||
typedef char arr_cv_42[42]; | ||
typedef char arr_vc_42[42]; | ||
} } | ||
|
||
|
||
|
@@ -548,9 +593,6 @@ namespace yes{ | |
|
||
namespace no{ | ||
|
||
typedef details::const_item const_item; | ||
typedef details::const_container const_container; | ||
|
||
class y{ | ||
private: | ||
y(){} | ||
|
@@ -567,6 +609,9 @@ namespace no{ | |
public: | ||
static singleton_t* instance(); | ||
}; | ||
|
||
typedef details::const_item const_item; | ||
typedef details::const_container const_container; | ||
} } | ||
|
||
namespace has_public_constructor{ | ||
|
@@ -663,6 +708,7 @@ namespace yes{ | |
const int yes2[2] = {0}; | ||
const volatile int yes3[2] = {0}; | ||
int yes4[2][3]; | ||
int const yes5[2] = {0}; | ||
} | ||
|
||
namespace no{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you are generating new instances, and return them. I think (I did not test this) that this may be a problem if a comparison needs to be done (using is_same() method for example). Could the types be retrieved by returning the right .base ?
The same comment holds for the remove_volatile() method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. If you have a type, say
t
, which isconst int
, thenis_same(t, remove_const(t))
will returnFalse
, which is correct. Butis_same(remove_const(t), remove_const(t))
should still returnTrue
(but I haven't tested this).I don't think you can get these right without creating new instances; what you have is nesting like this -
array_t -> const_t -> (type)
, and you need to remove theconst_t
from that hierarchy. But if you can think of a cleaner way to do this, I'm all for it. I really dislike thenake_type.base.base.base
part.