From 0f50322b3b1c6548b8b19663925872d9560c3760 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 10 Sep 2019 16:17:09 -0700 Subject: [PATCH] Treat multiple Ruby methods calling the same C method as aliases Previously, only calls to rb_define_alias were treated as aliases. This treats calls to rb_define_method with the same C function as aliases, with the first function defined being the primary method. This move the dedup code from the C parser to AnyMethod, and has AnyMethod look in its aliases to find the call_seq. Switch the deduplication code to remove lines matching one of the other aliases, instead of only keeping lines matching the current alias. The previous approach could eliminate all call_seq lines in cases where no line matched. This was necessary to pass tests when call_seq does deduplication by default. The only change to the darkfish template is to not perform unnecessary work by deduplicating twice. --- lib/rdoc/any_method.rb | 59 ++++++++++++-- .../generator/template/darkfish/class.rhtml | 4 +- lib/rdoc/parser/c.rb | 78 ++++++------------- 3 files changed, 76 insertions(+), 65 deletions(-) diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb index 9b0d309653..562e68461c 100644 --- a/lib/rdoc/any_method.rb +++ b/lib/rdoc/any_method.rb @@ -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 diff --git a/lib/rdoc/generator/template/darkfish/class.rhtml b/lib/rdoc/generator/template/darkfish/class.rhtml index 7733095086..596764ddc5 100644 --- a/lib/rdoc/generator/template/darkfish/class.rhtml +++ b/lib/rdoc/generator/template/darkfish/class.rhtml @@ -98,8 +98,8 @@ <% methods.each do |method| %>
"> - <% 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| %>
<%= h(call_seq.strip. diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb index 8265712370..707a898975 100644 --- a/lib/rdoc/parser/c.rb +++ b/lib/rdoc/parser/c.rb @@ -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