lib/rdoc/parser/c.rb in rdoc-3.4 vs lib/rdoc/parser/c.rb in rdoc-3.5
- old
+ new
@@ -283,40 +283,41 @@
\s*\(\s*([\w\.]+),
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
- %xm) do |type, var_name, meth_name, meth_body, param_count, source_file|
+ %xm) do |type, var_name, meth_name, function, param_count, source_file|
# Ignore top-object and weird struct.c dynamic stuff
next if var_name == "ruby_top_self"
next if var_name == "nstr"
next if var_name == "envtbl"
next if var_name == "argf" # it'd be nice to handle this one
var_name = "rb_cObject" if var_name == "rb_mKernel"
- handle_method(type, var_name, meth_name, meth_body, param_count,
+ handle_method(type, var_name, meth_name, function, param_count,
source_file)
end
@content.scan(%r%rb_define_global_function\s*\(
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
- %xm) do |meth_name, meth_body, param_count, source_file|
- handle_method("method", "rb_mKernel", meth_name,
- meth_body, param_count, source_file)
+ %xm) do |meth_name, function, param_count, source_file|
+ handle_method("method", "rb_mKernel", meth_name, function, param_count,
+ source_file)
end
@content.scan(/define_filetest_function\s*\(
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
- \s*(-?\w+)\s*\)/xm) do |meth_name, meth_body, param_count|
+ \s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count|
- handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
- handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
+ handle_method("method", "rb_mFileTest", meth_name, function, param_count)
+ handle_method("singleton_method", "rb_cFile", meth_name, function,
+ param_count)
end
end
##
# Finds the comment for an alias on +class_name+ from +new_name+ to
@@ -368,26 +369,25 @@
end
##
# Find the C code corresponding to a Ruby method
- def find_body(class_name, meth_name, meth_obj, body, quiet = false)
- case body
+ def find_body class_name, meth_name, meth_obj, file_content, quiet = false
+ case file_content
when %r%((?>/\*.*?\*/\s*)?)
((?:(?:static|SWIGINTERN)\s+)?
(?:intern\s+)?VALUE\s+#{meth_name}
- \s*(\([^)]*\))([^;]|$))%xm then
+ \s*(\(.*?\))([^;]|$))%xm then
comment = $1
- body_text = $2
+ body = $2
+ offset = $~.offset(2).first
remove_private_comments comment if comment
- # see if we can find the whole body
+ # try to find the whole body
+ body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content
- re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
- body_text = $& if /#{re}/m =~ body
-
# The comment block may have been overridden with a 'Document-method'
# block. This happens in the interpreter when multiple methods are
# vectored through to the same C method but those methods are logically
# distinct (for example Kernel.hash and Kernel.object_id share the same
# implementation
@@ -398,42 +398,57 @@
find_modifiers comment, meth_obj if comment
#meth_obj.params = params
meth_obj.start_collecting_tokens
tk = RDoc::RubyToken::Token.new nil, 1, 1
- tk.set_text body_text
+ tk.set_text body
meth_obj.add_token tk
meth_obj.comment = strip_stars comment
- when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m
+ meth_obj.offset = offset
+ meth_obj.line = file_content[0, offset].count("\n") + 1
+
+ body
+ when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m then
comment = $1
- body_text = $2
- find_body class_name, $3, meth_obj, body, true
+ body = $2
+ offset = $~.offset(2).first
+
+ find_body class_name, $3, meth_obj, file_content, true
find_modifiers comment, meth_obj
meth_obj.start_collecting_tokens
tk = RDoc::RubyToken::Token.new nil, 1, 1
- tk.set_text body_text
+ tk.set_text body
meth_obj.add_token tk
meth_obj.comment = strip_stars(comment) + meth_obj.comment.to_s
- when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m
- unless find_body(class_name, $1, meth_obj, body, true)
- warn "No definition for #{meth_name}" if @options.verbosity > 1
- return false
- end
+ meth_obj.offset = offset
+ meth_obj.line = file_content[0, offset].count("\n") + 1
+
+ body
+ when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m then
+ # with no comment we hope the aliased definition has it and use it's
+ # definition
+
+ body = find_body(class_name, $1, meth_obj, file_content, true)
+
+ return body if body
+
+ warn "No definition for #{meth_name}" if @options.verbosity > 1
+ false
else # No body, but might still have an override comment
comment = find_override_comment class_name, meth_obj.name
- if comment
+ if comment then
find_modifiers comment, meth_obj
meth_obj.comment = strip_stars comment
+
+ ''
else
warn "No definition for #{meth_name}" if @options.verbosity > 1
- return false
+ false
end
end
-
- true
end
##
# Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+
@@ -749,11 +764,11 @@
##
# Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned
# to +var_name+. +type+ is the type of method definition function used.
# +singleton_method+ and +module_function+ create a singleton method.
- def handle_method(type, var_name, meth_name, meth_body, param_count,
+ def handle_method(type, var_name, meth_name, function, param_count,
source_file = nil)
singleton = false
class_name = @known_classes[var_name]
unless class_name then
@@ -771,38 +786,40 @@
singleton = true
type = 'method' # force public
end
meth_obj = RDoc::AnyMethod.new '', meth_name
+ meth_obj.c_function = function
meth_obj.singleton =
singleton || %w[singleton_method module_function].include?(type)
p_count = Integer(param_count) rescue -1
- if p_count < 0 then
- meth_obj.params = "(*args)"
- elsif p_count == 0
- meth_obj.params = "()"
- else
- params = (1..p_count).map { |i| "p#{i}" }.join(', ')
- meth_obj.params = "(#{params})"
- end
-
if source_file then
file_name = File.join @file_dir, source_file
if File.exist? file_name then
- body = (@@known_bodies[file_name] ||= File.read(file_name))
+ file_content = (@@known_bodies[file_name] ||= File.read(file_name))
else
warn "unknown source #{source_file} for #{meth_name} in #{@file_name}"
end
else
- body = @content
+ file_content = @content
end
- if find_body(class_name, meth_body, meth_obj, body) and
- meth_obj.document_self then
+ body = find_body class_name, function, meth_obj, file_content
+
+ if body and meth_obj.document_self then
+ meth_obj.params = if p_count < -1 then # -2 is Array
+ '(*args)'
+ elsif p_count == -1 then # argc, argv
+ rb_scan_args body
+ else
+ "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})"
+ end
+
+
meth_obj.record_location @top_level
class_obj.add_method meth_obj
@stats.add_method meth_obj
meth_obj.visibility = :private if 'private_method' == type
end
@@ -857,9 +874,93 @@
''
end
end
comment
+ end
+
+ ##
+ # Extracts parameters from the +method_body+ and returns a method
+ # parameter string. Follows 1.9.3dev's scan-arg-spec, see README.EXT
+
+ def rb_scan_args method_body
+ method_body =~ /rb_scan_args\((.*?)\)/m
+ return '(*args)' unless $1
+
+ $1.split(/,/)[2] =~ /"(.*?)"/ # format argument
+ format = $1.split(//)
+
+ lead = opt = trail = 0
+
+ if format.first =~ /\d/ then
+ lead = $&.to_i
+ format.shift
+ if format.first =~ /\d/ then
+ opt = $&.to_i
+ format.shift
+ if format.first =~ /\d/ then
+ trail = $&.to_i
+ format.shift
+ block_arg = true
+ end
+ end
+ end
+
+ if format.first == '*' and not block_arg then
+ var = true
+ format.shift
+ if format.first =~ /\d/ then
+ trail = $&.to_i
+ format.shift
+ end
+ end
+
+ if format.first == ':' then
+ hash = true
+ format.shift
+ end
+
+ if format.first == '&' then
+ block = true
+ format.shift
+ end
+
+ # if the format string is not empty there's a bug in the C code, ignore it
+
+ args = []
+ position = 1
+
+ (1...(position + lead)).each do |index|
+ args << "p#{index}"
+ end
+
+ position += lead
+
+ (position...(position + opt)).each do |index|
+ args << "p#{index} = v#{index}"
+ end
+
+ position += opt
+
+ if var then
+ args << '*args'
+ position += 1
+ end
+
+ (position...(position + trail)).each do |index|
+ args << "p#{index}"
+ end
+
+ position += trail
+
+ if hash then
+ args << "p#{position} = {}"
+ position += 1
+ end
+
+ args << '&block' if block
+
+ "(#{args.join ', '})"
end
##
# Removes lines that are commented out that might otherwise get picked up
# when scanning for classes and methods