mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-06-24 22:40:31 +00:00
On some embedded platforms (real or simulated), when RAM and ROM are separate address spaces or RAM pointers are smaller than ROM pointers, the C keyword 'const' may (depending on compiler) be critical for differentiating between assembly code pointer types without having to use compiler-specific attribute flags to pick which address space a pointer refers to. (E.g. the M16C/R8C IAR C/C++ compiler in the Near (default) data model, where 'const char*' is a 3-byte pointer that can point anywhere in ROM or RAM, but 'char*' is a 2-byte pointer that can only point to RAM.)
This change causes CMock to preserve 'const' in argument types so that pointers-to-const continue to point to const data in the mocked code, while still removing the 'const' attribute from the pointers themselves.
This commit is contained in:
@@ -6,12 +6,13 @@
|
||||
|
||||
class CMockHeaderParser
|
||||
|
||||
attr_accessor :funcs, :c_attributes, :treat_as_void, :treat_externs
|
||||
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs
|
||||
|
||||
def initialize(cfg)
|
||||
@funcs = []
|
||||
@c_strippables = cfg.strippables
|
||||
@c_attributes = (['const'] + cfg.attributes).uniq
|
||||
@c_attr_noconst = cfg.attributes.uniq - ['const']
|
||||
@c_attributes = ['const'] + c_attr_noconst
|
||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
|
||||
@@ -144,11 +145,20 @@ class CMockHeaderParser
|
||||
arg_list.split(',').each do |arg|
|
||||
arg.strip!
|
||||
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
|
||||
|
||||
# Split up words and remove known attributes, but in case of pointer args, don't remove any
|
||||
# 'const' from the type that it points to, since that may change the underlying assembly-code
|
||||
# pointer type on some embedded platforms, making it point to RAM instead of ROM. (I.e. For
|
||||
# pointer args, remove 'const' only when it applies to the pointer itself. For non-pointer
|
||||
# args, remove 'const' regardless.)
|
||||
#
|
||||
arg_array = arg.split
|
||||
arg_elements = arg_array - @c_attributes # split up words and remove known attributes
|
||||
args << { :type => (arg_type = arg_elements[0..-2].join(' ')),
|
||||
ptr_const_info = divine_ptr_and_const(arg)
|
||||
arg_elements = arg_array - (ptr_const_info[:ptr?] ? @c_attr_noconst : @c_attributes)
|
||||
ptr_const_info = divine_ptr_and_const(arg)
|
||||
args << { :type => arg_elements[0..(ptr_const_info[:const_ptr?] ? -3 : -2)].join(' '),
|
||||
:name => arg_elements[-1]
|
||||
}.merge(divine_ptr_and_const(arg))
|
||||
}.merge(ptr_const_info)
|
||||
end
|
||||
return args
|
||||
end
|
||||
|
||||
@@ -828,6 +828,69 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "properly parse const and pointer argument types with no arg names" do
|
||||
|
||||
source = "void foo(char const*, char*const, const char*, const char*const, char const*const, char*, char, const char);\n"
|
||||
|
||||
expected = [{ :name => "foo",
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "char const* cmock_arg1, char* const cmock_arg2, const char* cmock_arg3, const char* const cmock_arg4, " +
|
||||
"char const* const cmock_arg5, char* cmock_arg6, char cmock_arg7, const char cmock_arg8",
|
||||
:args => [{ :type=>"char const*", :name => "cmock_arg1", :ptr? => true, :const? => true, :const_ptr? => false },
|
||||
{ :type=>"char*", :name => "cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => true },
|
||||
{ :type=>"const char*", :name => "cmock_arg3", :ptr? => true, :const? => true, :const_ptr? => false },
|
||||
{ :type=>"const char*", :name => "cmock_arg4", :ptr? => true, :const? => true, :const_ptr? => true },
|
||||
{ :type=>"char const*", :name => "cmock_arg5", :ptr? => true, :const? => true, :const_ptr? => true },
|
||||
{ :type=>"char*", :name => "cmock_arg6", :ptr? => true, :const? => false, :const_ptr? => false },
|
||||
{ :type=>"char", :name => "cmock_arg7", :ptr? => false, :const? => false, :const_ptr? => false },
|
||||
{ :type=>"char", :name => "cmock_arg8", :ptr? => false, :const? => true, :const_ptr? => false }],
|
||||
:args_call => "cmock_arg1, cmock_arg2, cmock_arg3, cmock_arg4, cmock_arg5, cmock_arg6, cmock_arg7, cmock_arg8",
|
||||
:contains_ptr? => true
|
||||
}]
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "properly parse const and pointer argument types with arg names" do
|
||||
|
||||
source = "void bar(char const* param1, char*const param2, const char* param3, const char*const param4,\n" +
|
||||
" char const*const param5, char*param6, char param7, const char param8);\n"
|
||||
|
||||
expected = [{ :name => "bar",
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "char const* param1, char* const param2, const char* param3, const char* const param4, " +
|
||||
"char const* const param5, char* param6, char param7, const char param8",
|
||||
:args => [{ :type=>"char const*", :name => "param1", :ptr? => true, :const? => true, :const_ptr? => false },
|
||||
{ :type=>"char*", :name => "param2", :ptr? => true, :const? => false, :const_ptr? => true },
|
||||
{ :type=>"const char*", :name => "param3", :ptr? => true, :const? => true, :const_ptr? => false },
|
||||
{ :type=>"const char*", :name => "param4", :ptr? => true, :const? => true, :const_ptr? => true },
|
||||
{ :type=>"char const*", :name => "param5", :ptr? => true, :const? => true, :const_ptr? => true },
|
||||
{ :type=>"char*", :name => "param6", :ptr? => true, :const? => false, :const_ptr? => false },
|
||||
{ :type=>"char", :name => "param7", :ptr? => false, :const? => false, :const_ptr? => false },
|
||||
{ :type=>"char", :name => "param8", :ptr? => false, :const? => true, :const_ptr? => false }],
|
||||
:args_call => "param1, param2, param3, param4, param5, param6, param7, param8",
|
||||
:contains_ptr? => true
|
||||
}]
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "properly detect typedef'd variants of void and use those" do
|
||||
|
||||
source = "typedef (void) FUNKY_VOID_T;\n" +
|
||||
@@ -904,7 +967,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:name=>"Penny",
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"struct _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
|
||||
:args=>[ {:type=>"struct const _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
|
||||
:args_string=>"struct const _KeepYourHeadUp_* const BillyBuddy",
|
||||
:args_call=>"BillyBuddy"
|
||||
},
|
||||
@@ -1407,7 +1470,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"sqlite3_stmt*", :name=>"cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
{:type=>"int", :name=>"cmock_arg3", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
{:type=>"char*", :name=>"cmock_arg4", :ptr? => true, :const? => true, :const_ptr? => false},
|
||||
{:type=>"const char*", :name=>"cmock_arg4", :ptr? => true, :const? => true, :const_ptr? => false},
|
||||
{:type=>"int", :name=>"n", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
{:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user