Skip to content

Commit 082758f

Browse files
committed
Record C implementation function for methods, make find_body more robust.
1 parent a37e2cd commit 082758f

File tree

4 files changed

+64
-45
lines changed

4 files changed

+64
-45
lines changed

History.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
* RDoc::Parser::C looks for rb_scan_args and fills in RDoc::AnyMethod#params
55
appropriately. This may provide useful information if the author did not
66
provide a call-seq.
7+
* RDoc::Parser::C now records the function name for methods implemented in
8+
C.
79
* Bug fixes
810
* Locations of module aliases are now recorded.
11+
* RDoc::Parser::C finds method bodies better now.
912

1013
=== 3.4
1114

lib/rdoc/any_method.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ class RDoc::AnyMethod < RDoc::MethodAttr
1313

1414
attr_accessor :dont_rename_initialize
1515

16+
##
17+
# The C function that implements this method (if it was defined in a C file)
18+
19+
attr_accessor :c_function
20+
1621
##
1722
# Different ways to call this method
1823

@@ -31,8 +36,9 @@ class RDoc::AnyMethod < RDoc::MethodAttr
3136
def initialize text, name
3237
super
3338

39+
@c_function = nil
3440
@dont_rename_initialize = false
35-
@token_stream = nil
41+
@token_stream = nil
3642
end
3743

3844
##

lib/rdoc/parser/c.rb

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def do_methods
285285
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
286286
\s*(-?\w+)\s*\)
287287
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
288-
%xm) do |type, var_name, meth_name, meth_body, param_count, source_file|
288+
%xm) do |type, var_name, meth_name, function, param_count, source_file|
289289

290290
# Ignore top-object and weird struct.c dynamic stuff
291291
next if var_name == "ruby_top_self"
@@ -294,7 +294,7 @@ def do_methods
294294
next if var_name == "argf" # it'd be nice to handle this one
295295

296296
var_name = "rb_cObject" if var_name == "rb_mKernel"
297-
handle_method(type, var_name, meth_name, meth_body, param_count,
297+
handle_method(type, var_name, meth_name, function, param_count,
298298
source_file)
299299
end
300300

@@ -303,18 +303,19 @@ def do_methods
303303
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
304304
\s*(-?\w+)\s*\)
305305
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
306-
%xm) do |meth_name, meth_body, param_count, source_file|
307-
handle_method("method", "rb_mKernel", meth_name,
308-
meth_body, param_count, source_file)
306+
%xm) do |meth_name, function, param_count, source_file|
307+
handle_method("method", "rb_mKernel", meth_name, function, param_count,
308+
source_file)
309309
end
310310

311311
@content.scan(/define_filetest_function\s*\(
312312
\s*"([^"]+)",
313313
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
314-
\s*(-?\w+)\s*\)/xm) do |meth_name, meth_body, param_count|
314+
\s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count|
315315

316-
handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
317-
handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
316+
handle_method("method", "rb_mFileTest", meth_name, function, param_count)
317+
handle_method("singleton_method", "rb_cFile", meth_name, function,
318+
param_count)
318319
end
319320
end
320321

@@ -370,21 +371,20 @@ def find_attr_comment var_name, attr_name, read = nil, write = nil
370371
##
371372
# Find the C code corresponding to a Ruby method
372373

373-
def find_body(class_name, meth_name, meth_obj, body, quiet = false)
374-
case body
374+
def find_body class_name, meth_name, meth_obj, file_content, quiet = false
375+
case file_content
375376
when %r%((?>/\*.*?\*/\s*)?)
376377
((?:(?:static|SWIGINTERN)\s+)?
377378
(?:intern\s+)?VALUE\s+#{meth_name}
378379
\s*(\([^)]*\))([^;]|$))%xm then
379380
comment = $1
380-
body_text = $2
381+
body = $2
381382

382383
remove_private_comments comment if comment
383384

384385
# see if we can find the whole body
385386

386-
re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
387-
body_text = $& if /#{re}/m =~ body
387+
body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content
388388

389389
# The comment block may have been overridden with a 'Document-method'
390390
# block. This happens in the interpreter when multiple methods are
@@ -400,38 +400,44 @@ def find_body(class_name, meth_name, meth_obj, body, quiet = false)
400400
#meth_obj.params = params
401401
meth_obj.start_collecting_tokens
402402
tk = RDoc::RubyToken::Token.new nil, 1, 1
403-
tk.set_text body_text
403+
tk.set_text body
404404
meth_obj.add_token tk
405405
meth_obj.comment = strip_stars comment
406-
when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m
406+
407+
body
408+
when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m then
407409
comment = $1
408-
body_text = $2
409-
find_body class_name, $3, meth_obj, body, true
410+
body = $2
411+
find_body class_name, $3, meth_obj, file_content, true
410412
find_modifiers comment, meth_obj
411413

412414
meth_obj.start_collecting_tokens
413415
tk = RDoc::RubyToken::Token.new nil, 1, 1
414-
tk.set_text body_text
416+
tk.set_text body
415417
meth_obj.add_token tk
416418
meth_obj.comment = strip_stars(comment) + meth_obj.comment.to_s
417-
when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m
418-
unless find_body(class_name, $1, meth_obj, body, true)
419-
warn "No definition for #{meth_name}" if @options.verbosity > 1
420-
return false
421-
end
419+
420+
body
421+
when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m then
422+
body = find_body(class_name, $1, meth_obj, file_content, true)
423+
424+
return body if body
425+
426+
warn "No definition for #{meth_name}" if @options.verbosity > 1
427+
false
422428
else # No body, but might still have an override comment
423429
comment = find_override_comment class_name, meth_obj.name
424430

425-
if comment
431+
if comment then
426432
find_modifiers comment, meth_obj
427433
meth_obj.comment = strip_stars comment
434+
435+
''
428436
else
429437
warn "No definition for #{meth_name}" if @options.verbosity > 1
430-
return false
438+
false
431439
end
432440
end
433-
434-
true
435441
end
436442

437443
##
@@ -751,7 +757,7 @@ def handle_ifdefs_in(body)
751757
# to +var_name+. +type+ is the type of method definition function used.
752758
# +singleton_method+ and +module_function+ create a singleton method.
753759

754-
def handle_method(type, var_name, meth_name, meth_body, param_count,
760+
def handle_method(type, var_name, meth_name, function, param_count,
755761
source_file = nil)
756762
singleton = false
757763
class_name = @known_classes[var_name]
@@ -773,33 +779,36 @@ def handle_method(type, var_name, meth_name, meth_body, param_count,
773779
end
774780

775781
meth_obj = RDoc::AnyMethod.new '', meth_name
782+
meth_obj.c_function = function
776783
meth_obj.singleton =
777784
singleton || %w[singleton_method module_function].include?(type)
778785

779786
p_count = Integer(param_count) rescue -1
780787

781-
meth_obj.params = if p_count < -1 then # -2 is Array
782-
'(*args)'
783-
elsif p_count == -1 then # argc, argv
784-
rb_scan_args meth_body
785-
else
786-
"(#{(1..p_count).map { |i| "p#{i}" }.join ', '})"
787-
end
788-
789788
if source_file then
790789
file_name = File.join @file_dir, source_file
791790

792791
if File.exist? file_name then
793-
body = (@@known_bodies[file_name] ||= File.read(file_name))
792+
file_content = (@@known_bodies[file_name] ||= File.read(file_name))
794793
else
795794
warn "unknown source #{source_file} for #{meth_name} in #{@file_name}"
796795
end
797796
else
798-
body = @content
797+
file_content = @content
799798
end
800799

801-
if find_body(class_name, meth_body, meth_obj, body) and
802-
meth_obj.document_self then
800+
body = find_body class_name, function, meth_obj, file_content
801+
802+
if body and meth_obj.document_self then
803+
meth_obj.params = if p_count < -1 then # -2 is Array
804+
'(*args)'
805+
elsif p_count == -1 then # argc, argv
806+
rb_scan_args body
807+
else
808+
"(#{(1..p_count).map { |i| "p#{i}" }.join ', '})"
809+
end
810+
811+
803812
meth_obj.record_location @top_level
804813
class_obj.add_method meth_obj
805814
@stats.add_method meth_obj

test/test_rdoc_parser_c.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def test_find_body
536536

537537
code = other_function.token_stream.first.text
538538

539-
assert_equal "VALUE\nother_function() ", code
539+
assert_equal "VALUE\nother_function() {\n}", code
540540
end
541541

542542
def test_find_body_2
@@ -806,15 +806,15 @@ def test_handle_method_args_2
806806
def test_handle_method_args_minus_1
807807
parser = util_parser "Document-method: Object#m\n blah */"
808808

809-
body = <<-BODY
809+
parser.content = <<-BODY
810810
VALUE
811-
m(int argc, VALUE *argv, VALUE obj) {
811+
rb_m(int argc, VALUE *argv, VALUE obj) {
812812
VALUE o1, o2;
813813
rb_scan_args(argc, argv, "1", &o1, &o2);
814814
}
815815
BODY
816816

817-
parser.handle_method 'method', 'rb_cObject', 'm', body, -1
817+
parser.handle_method 'method', 'rb_cObject', 'm', 'rb_m', -1
818818

819819
m = @top_level.find_module_named('Object').method_list.first
820820

@@ -887,6 +887,7 @@ def test_define_method
887887
read_method = klass.method_list.first
888888
assert_equal "read", read_method.name
889889
assert_equal "Method Comment! ", read_method.comment
890+
assert_equal "rb_io_s_read", read_method.c_function
890891
assert read_method.singleton
891892
end
892893

0 commit comments

Comments
 (0)