Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat multiple Ruby methods calling the same C method as aliases #742

Merged
merged 1 commit into from
Mar 6, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions lib/rdoc/any_method.rb
Original file line number Diff line number Diff line change
@@ -26,12 +26,6 @@ class RDoc::AnyMethod < RDoc::MethodAttr

attr_accessor :c_function

##
# Different ways to call this method

attr_reader :call_seq

##
# Parameters for this method

attr_accessor :params
@@ -93,6 +87,19 @@ def arglists
end
end

##
# Different ways to call this method

def call_seq
unless call_seq = _call_seq
call_seq = is_alias_for._call_seq if is_alias_for
end

return unless call_seq

deduplicate_call_seq(call_seq)
end

##
# Sets the different ways you can call this method. If an empty +call_seq+
# is given nil is assumed.
@@ -312,5 +319,43 @@ def superclass_method
@superclass_method
end

end
protected

##
# call_seq without deduplication and alias lookup.

def _call_seq
@call_seq if defined?(@call_seq) && @call_seq
end

private

##
# call_seq with alias examples information removed, if this
# method is an alias method.

def deduplicate_call_seq(call_seq)
return call_seq unless is_alias_for || !aliases.empty?

method_name = self.name
method_name = method_name[0, 1] if method_name =~ /\A\[/

entries = call_seq.split "\n"

ignore = aliases.map(&:name)
if is_alias_for
ignore << is_alias_for.name
ignore.concat is_alias_for.aliases.map(&:name)
end
ignore.map! { |n| n =~ /\A\[/ ? n[0, 1] : n}
ignore.delete(method_name)
ignore = Regexp.union(ignore)

matching = entries.reject do |entry|
entry =~ /^\w*\.?#{ignore}/ or
entry =~ /\s#{ignore}\s/
end

matching.join "\n"
end
end
4 changes: 2 additions & 2 deletions lib/rdoc/generator/template/darkfish/class.rhtml
Original file line number Diff line number Diff line change
@@ -98,8 +98,8 @@

<% methods.each do |method| %>
<div id="<%= method.aref %>" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
<% if method.call_seq then %>
<% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
<% if (call_seq = method.call_seq) then %>
<% call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
<div class="method-heading">
<span class="method-callseq">
<%= h(call_seq.strip.
78 changes: 22 additions & 56 deletions lib/rdoc/parser/c.rb
Original file line number Diff line number Diff line change
@@ -209,48 +209,6 @@ def @enclosure_dependencies.tsort_each_child node, &block
end
end

##
# Removes duplicate call-seq entries for methods using the same
# implementation.

def deduplicate_call_seq
@methods.each do |var_name, functions|
class_name = @known_classes[var_name]
next unless class_name
class_obj = find_class var_name, class_name

functions.each_value do |method_names|
next if method_names.length == 1

method_names.each do |method_name|
deduplicate_method_name class_obj, method_name
end
end
end
end

##
# If two ruby methods share a C implementation (and comment) this
# deduplicates the examples in the call_seq for the method to reduce
# confusion in the output.

def deduplicate_method_name class_obj, method_name # :nodoc:
return unless
method = class_obj.method_list.find { |m| m.name == method_name }
return unless call_seq = method.call_seq

method_name = method_name[0, 1] if method_name =~ /\A\[/

entries = call_seq.split "\n"

matching = entries.select do |entry|
entry =~ /^\w*\.?#{Regexp.escape method_name}/ or
entry =~ /\s#{Regexp.escape method_name}\s/
end

method.call_seq = matching.join "\n"
end

##
# Scans #content for rb_define_alias

@@ -269,23 +227,29 @@ def do_aliases
end

class_obj = find_class var_name, class_name

al = RDoc::Alias.new '', old_name, new_name, ''
al.singleton = @singleton_classes.key? var_name

comment = find_alias_comment var_name, new_name, old_name

comment.normalize

al.comment = comment

al.record_location @top_level

class_obj.add_alias al
@stats.add_alias al
if comment.to_s.empty? and existing_method = class_obj.method_list.find { |m| m.name == old_name}
comment = existing_method.comment
end
add_alias(var_name, class_obj, old_name, new_name, comment)
end
end

##
# Add alias, either from a direct alias definition, or from two
# method that reference the same function.

def add_alias(var_name, class_obj, old_name, new_name, comment)
al = RDoc::Alias.new '', old_name, new_name, ''
al.singleton = @singleton_classes.key? var_name
al.comment = comment
al.record_location @top_level
class_obj.add_alias al
@stats.add_alias al
al
end

##
# Scans #content for rb_attr and rb_define_attr

@@ -1021,6 +985,10 @@ def handle_method(type, var_name, meth_name, function, param_count,

class_obj = find_class var_name, class_name

if existing_method = class_obj.method_list.find { |m| m.c_function == function }
add_alias(var_name, class_obj, existing_method.name, meth_name, existing_method.comment)
end

if class_obj then
if meth_name == 'initialize' then
meth_name = 'new'
@@ -1249,8 +1217,6 @@ def scan
do_aliases
do_attrs

deduplicate_call_seq

@store.add_c_variables self

@top_level