mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-08-08 20:27:50 +00:00
Merge pull request #141 from jlindgren90/fix-const-parsing
Fix const determination for pointer-to-pointer types. (Thanks John! (@jlindgren90) )
This commit is contained in:
+17
-26
@@ -146,44 +146,35 @@ class CMockHeaderParser
|
||||
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
|
||||
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(' ')),
|
||||
args << { :type => arg_elements[0..-2].join(' '),
|
||||
:name => arg_elements[-1]
|
||||
}.merge(divine_ptr_and_const(arg))
|
||||
end
|
||||
return args
|
||||
end
|
||||
|
||||
def divine_ptr(arg_type)
|
||||
return false unless arg_type.include? '*'
|
||||
return false if arg_type.gsub(/(const|char|\*|\s)+/,'').empty?
|
||||
def divine_ptr(arg)
|
||||
return false unless arg.include? '*'
|
||||
# treat "const char *" and similar as a string, not a pointer
|
||||
return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg
|
||||
return true
|
||||
end
|
||||
|
||||
def divine_const(arg)
|
||||
return false if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg) # check for const as part of a larger word
|
||||
return true if (/const(?:\w|\s)*\*/ =~ arg) # check const comes before * indicating const data
|
||||
return false if (/\*\s*const/ =~ arg) # check const comes after * indicating const ptr
|
||||
return true
|
||||
# a non-pointer arg containing "const" is a constant
|
||||
# an arg containing "const" before the last * is a pointer to a constant
|
||||
return ( arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg)
|
||||
: (/(^|\s)const(\s|$)/ =~ arg) ) ? true : false
|
||||
end
|
||||
|
||||
def divine_ptr_and_const(arg)
|
||||
divination = { :ptr? => false, :const? => false, :const_ptr? => false }
|
||||
divination = {}
|
||||
|
||||
#first check if there is a pointer present and that it's not part of a C string or function definition
|
||||
#divination[:ptr?] = (arg.split[0..-2].join.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?)
|
||||
divination[:ptr?] = (arg.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?)
|
||||
divination[:ptr?] = divine_ptr(arg)
|
||||
divination[:const?] = divine_const(arg)
|
||||
|
||||
#if there isn't a const that isn't part of a larger word, we're done
|
||||
return divination if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg)
|
||||
divination[:const?] = true
|
||||
|
||||
# check const comes after * indicating const ptr
|
||||
if (/\*\s*const/ =~ arg)
|
||||
divination[:const_ptr?] = true
|
||||
|
||||
#check const comes before * indicating also const data
|
||||
divination[:const?] = (/const(?:\w|\s)*\*/ =~ arg) ? true : false
|
||||
end
|
||||
# an arg containing "const" after the last * is a constant pointer
|
||||
divination[:const_ptr?] = (/\*(?!.*\*)\s*const(\s|$)/ =~ arg) ? true : false
|
||||
|
||||
return divination
|
||||
end
|
||||
@@ -237,8 +228,8 @@ class CMockHeaderParser
|
||||
|
||||
#process function attributes, return type, and name
|
||||
descriptors = regex_match[1]
|
||||
descriptors.gsub!(/\s+\*/,'*') #remove space to place asterisks with return type (where they belong)
|
||||
descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from function name to place asterisks with return type (where they belong)
|
||||
descriptors.gsub!(/(\w)\*/,'\1 *') #pull asterisks away from preceding word
|
||||
descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from following word
|
||||
descriptors = descriptors.split #array of all descriptor strings
|
||||
|
||||
#grab name
|
||||
@@ -258,7 +249,7 @@ class CMockHeaderParser
|
||||
end
|
||||
end
|
||||
decl[:modifier] = decl[:modifier].join(' ')
|
||||
rettype = rettype.join(' ')
|
||||
rettype = rettype.join(' ').gsub(/\s+\*/,'*') #remove space before asterisks
|
||||
rettype = 'void' if (@local_as_void.include?(rettype.strip))
|
||||
decl[:return] = { :type => rettype,
|
||||
:name => 'cmock_to_return',
|
||||
|
||||
@@ -805,6 +805,39 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "should properly handle const before or after return type" do
|
||||
|
||||
sources = [
|
||||
"const int * PorkRoast(void);\n",
|
||||
"int const * PorkRoast(void);\n",
|
||||
"const int* PorkRoast(void);\n",
|
||||
"int const* PorkRoast(void);\n",
|
||||
"const int *PorkRoast(void);\n",
|
||||
"int const *PorkRoast(void);\n"
|
||||
]
|
||||
|
||||
expected = [{ :var_arg=>nil,
|
||||
:name=>"PorkRoast",
|
||||
:return=> { :type => "int*",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => true,
|
||||
:const? => true,
|
||||
:const_ptr? => false,
|
||||
:str => "int* cmock_to_return",
|
||||
:void? => false
|
||||
},
|
||||
:modifier=>"const",
|
||||
:contains_ptr? => false,
|
||||
:args=>[],
|
||||
:args_string=>"void",
|
||||
:args_call=>""
|
||||
}]
|
||||
|
||||
sources.each do |source|
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
end
|
||||
|
||||
it "should properly handle const applied after asterisk in return type (not legal C, but sometimes used)" do
|
||||
|
||||
source = "int * const PorkRoast(void);\n"
|
||||
@@ -1052,7 +1085,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, result[:functions])
|
||||
end
|
||||
|
||||
it "handle arrays and treat them as pointers" do
|
||||
it "handle arrays and treat them as pointers or strings" do
|
||||
source = "void KeyOperated(CUSTOM_TYPE thing1[], int thing2 [ ], char thing3 [][2 ][ 3], int* thing4[4])"
|
||||
expected = [{:var_arg=>nil,
|
||||
:return=>{ :type => "void",
|
||||
@@ -1068,7 +1101,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"CUSTOM_TYPE*", :name=>"thing1", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
{:type=>"int*", :name=>"thing2", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
{:type=>"char*", :name=>"thing3", :ptr? => true, :const? => false, :const_ptr? => false}, #THIS one will likely change in the future when we improve multidimensional array support
|
||||
{:type=>"char*", :name=>"thing3", :ptr? => false, :const? => false, :const_ptr? => false}, #THIS one will likely change in the future when we improve multidimensional array support
|
||||
{:type=>"int**", :name=>"thing4", :ptr? => true, :const? => false, :const_ptr? => false} #THIS one will likely change in the future when we improve multidimensional array support
|
||||
],
|
||||
:args_string=>"CUSTOM_TYPE* thing1, int* thing2, char* thing3, int** thing4",
|
||||
@@ -1407,7 +1440,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=>"char*", :name=>"cmock_arg4", :ptr? => false, :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}
|
||||
],
|
||||
@@ -1510,4 +1543,69 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "divines all permutations of ptr, const, and const_ptr correctly" do
|
||||
truth_table = [
|
||||
# argument ptr const const_ptr
|
||||
[ "constNOTconst constNOTconst", false, false, false ],
|
||||
[ "const constNOTconst constNOTconst", false, true, false ],
|
||||
[ "constNOTconst const constNOTconst", false, true, false ],
|
||||
[ "constNOTconst *constNOTconst", true, false, false ],
|
||||
[ "const constNOTconst *constNOTconst", true, true, false ],
|
||||
[ "constNOTconst const *constNOTconst", true, true, false ],
|
||||
[ "constNOTconst *const constNOTconst", true, false, true ],
|
||||
[ "const constNOTconst *const constNOTconst", true, true, true ],
|
||||
[ "constNOTconst const *const constNOTconst", true, true, true ],
|
||||
[ "constNOTconst **constNOTconst", true, false, false ],
|
||||
[ "const constNOTconst **constNOTconst", true, false, false ],
|
||||
[ "constNOTconst const **constNOTconst", true, false, false ],
|
||||
[ "constNOTconst *const *constNOTconst", true, true, false ],
|
||||
[ "const constNOTconst *const *constNOTconst", true, true, false ],
|
||||
[ "constNOTconst const *const *constNOTconst", true, true, false ],
|
||||
[ "constNOTconst **const constNOTconst", true, false, true ],
|
||||
[ "const constNOTconst **const constNOTconst", true, false, true ],
|
||||
[ "constNOTconst const **const constNOTconst", true, false, true ],
|
||||
[ "constNOTconst *const *const constNOTconst", true, true, true ],
|
||||
[ "const constNOTconst *const *const constNOTconst", true, true, true ],
|
||||
[ "constNOTconst const *const *const constNOTconst", true, true, true ]
|
||||
]
|
||||
|
||||
truth_table.each do |entry|
|
||||
assert_equal(@parser.divine_ptr(entry[0]), entry[1])
|
||||
assert_equal(@parser.divine_const(entry[0]), entry[2])
|
||||
assert_equal(@parser.divine_ptr_and_const(entry[0]),
|
||||
{ ptr?: entry[1], const?: entry[2], const_ptr?: entry[3] })
|
||||
end
|
||||
end
|
||||
|
||||
it "divines ptr correctly for string types" do
|
||||
truth_table = [
|
||||
# argument ptr
|
||||
[ "char s", false ],
|
||||
[ "const char s", false ],
|
||||
[ "char const s", false ],
|
||||
[ "char *s", false ],
|
||||
[ "const char *s", false ],
|
||||
[ "char const *s", false ],
|
||||
[ "char *const s", false ],
|
||||
[ "const char *const s", false ],
|
||||
[ "char const *const s", false ],
|
||||
[ "char **s", true ],
|
||||
[ "const char **s", true ],
|
||||
[ "char const **s", true ],
|
||||
[ "char *const *s", true ],
|
||||
[ "const char *const *s", true ],
|
||||
[ "char const *const *s", true ],
|
||||
[ "char **const s", true ],
|
||||
[ "const char **const s", true ],
|
||||
[ "char const **const s", true ],
|
||||
[ "char *const *const s", true ],
|
||||
[ "const char *const *const s", true ],
|
||||
[ "char const *const *const s", true ]
|
||||
]
|
||||
|
||||
truth_table.each do |entry|
|
||||
assert_equal(@parser.divine_ptr(entry[0]), entry[1])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user