diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index c910052..42f5586 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -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 diff --git a/test/unit/cmock_header_parser_test.rb b/test/unit/cmock_header_parser_test.rb index a3d4a45..32b811d 100644 --- a/test/unit/cmock_header_parser_test.rb +++ b/test/unit/cmock_header_parser_test.rb @@ -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} ],