Skip to content

Commit b792230

Browse files
committed
Separate C call-seq for "copied" methods
If the same C function is used to implement two methods typically the call-seq in the comment describes both methods together. This leads to confusing duplication in generated HTML as identical content is show twice. Now when such a method is encountered the call-seq is de-duplicated to avoid this confusion.
1 parent 78d5754 commit b792230

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

History.rdoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* Code objects with nodoc are no longer included in the ri store. Bug #177
2626
by Thomas Leitner.
2727
* Text#snippet now creates a RDoc::Markup::ToHtmlSnippet correctly.
28+
* The C parser now de-duplicates call-seq if the same C function is used for
29+
multiple method names. Bug #203 by Pete Higgins
2830

2931
=== 4.0.0 / 2013-02-24
3032

lib/rdoc/parser/c.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ def initialize top_level, file_name, content, options, stats
173173
@classes = load_variable_map :c_class_variables
174174
@singleton_classes = load_variable_map :c_singleton_class_variables
175175

176+
# class_variable => { function => [method, ...] }
177+
@methods = Hash.new { |h, f| h[f] = Hash.new { |h, m| h[m] = [] } }
178+
176179
# missing variable => [handle_class_module arguments]
177180
@missing_dependencies = {}
178181

@@ -206,6 +209,41 @@ def @enclosure_dependencies.tsort_each_child node, &block
206209
end
207210
end
208211

212+
##
213+
# Removes duplicate call-seq entries for methods using the same
214+
# implementation.
215+
216+
def deduplicate_call_seq
217+
@methods.each do |var_name, functions|
218+
class_name = @known_classes[var_name]
219+
class_obj = find_class var_name, class_name
220+
221+
functions.each_value do |method_names|
222+
next if method_names.length == 1
223+
224+
method_names.each do |method_name|
225+
deduplicate_method_name class_obj, method_name
226+
end
227+
end
228+
end
229+
end
230+
231+
def deduplicate_method_name class_obj, method_name
232+
return unless
233+
method = class_obj.method_list.find { |m| m.name == method_name }
234+
return unless call_seq = method.call_seq
235+
236+
method_name = method_name[0] unless method_name =~ /\A\w/
237+
238+
entries = call_seq.split "\n"
239+
240+
matching = entries.select do |entry|
241+
entry =~ /^\w*\.?#{Regexp.escape method_name}/
242+
end
243+
244+
method.call_seq = matching.join "\n"
245+
end
246+
209247
##
210248
# Scans #content for rb_define_alias
211249

@@ -938,6 +976,8 @@ def handle_method(type, var_name, meth_name, function, param_count,
938976
class_name = @known_classes[var_name]
939977
singleton = @singleton_classes.key? var_name
940978

979+
@methods[var_name][function] << meth_name
980+
941981
return unless class_name
942982

943983
class_obj = find_class var_name, class_name
@@ -1172,6 +1212,8 @@ def scan
11721212
do_aliases
11731213
do_attrs
11741214

1215+
deduplicate_call_seq
1216+
11751217
@store.add_c_variables self
11761218

11771219
@top_level

test/test_rdoc_parser_c.rb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,80 @@ def test_scan
16991699
assert_equal expected, @store.c_singleton_class_variables
17001700
end
17011701

1702+
def test_scan_method_copy
1703+
parser = util_parser <<-C
1704+
/*
1705+
* call-seq:
1706+
* pathname.to_s -> string
1707+
* pathname.to_path -> string
1708+
*
1709+
* Return the path as a String.
1710+
*
1711+
* to_path is implemented so Pathname objects are usable with File.open, etc.
1712+
*/
1713+
static VALUE
1714+
path_to_s(VALUE self) { }
1715+
1716+
/*
1717+
* call-seq:
1718+
* str[index] -> new_str or nil
1719+
* str[start, length] -> new_str or nil
1720+
* str.slice(index) -> new_str or nil
1721+
* str.slice(start, length) -> new_str or nil
1722+
*/
1723+
static VALUE
1724+
path_aref_m(int argc, VALUE *argv, VALUE str) { }
1725+
1726+
/*
1727+
* call-seq:
1728+
* string <=> other_string -> -1, 0, +1 or nil
1729+
*/
1730+
static VALUE
1731+
path_cmp_m(VALUE str1, VALUE str2) { }
1732+
1733+
Init_pathname()
1734+
{
1735+
rb_cPathname = rb_define_class("Pathname", rb_cObject);
1736+
1737+
rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
1738+
rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
1739+
rb_define_method(rb_cPathname, "[]", path_aref_m, -1);
1740+
rb_define_method(rb_cPathname, "slice", path_aref_m, -1);
1741+
rb_define_method(rb_cPathname, "<=>", path_cmp_m, 1);
1742+
}
1743+
C
1744+
1745+
parser.scan
1746+
1747+
pathname = @store.classes_hash['Pathname']
1748+
1749+
to_path = pathname.method_list.find { |m| m.name == 'to_path' }
1750+
assert_equal "pathname.to_path -> string", to_path.call_seq
1751+
1752+
to_s = pathname.method_list.find { |m| m.name == 'to_s' }
1753+
assert_equal "pathname.to_s -> string", to_s.call_seq
1754+
1755+
index_expected = <<-EXPECTED.chomp
1756+
str[index] -> new_str or nil
1757+
str[start, length] -> new_str or nil
1758+
EXPECTED
1759+
1760+
index = pathname.method_list.find { |m| m.name == '[]' }
1761+
assert_equal index_expected, index.call_seq, '[]'
1762+
1763+
slice_expected = <<-EXPECTED.chomp
1764+
str.slice(index) -> new_str or nil
1765+
str.slice(start, length) -> new_str or nil
1766+
EXPECTED
1767+
1768+
slice = pathname.method_list.find { |m| m.name == 'slice' }
1769+
assert_equal slice_expected, slice.call_seq
1770+
1771+
spaceship = pathname.method_list.find { |m| m.name == '<=>' }
1772+
assert_equal "string <=> other_string -> -1, 0, +1 or nil",
1773+
spaceship.call_seq
1774+
end
1775+
17021776
def test_scan_order_dependent
17031777
parser = util_parser <<-C
17041778
void a(void) {

0 commit comments

Comments
 (0)