From 1054ba60462c9f4c090112a9fc1a68a1f54cbd94 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:01:42 +0200 Subject: [PATCH] Fix alias detection for multiple `rb_define_singleton_method` They were not detected because `singleton_classes` doesn't contain the variable. Fix this simply by moving the check for `singleton_method` further up. Closes #1722 --- lib/rdoc/parser/c.rb | 11 ++++---- test/rdoc/parser/c_test.rb | 57 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb index 4a76e22b6d..db143a7119 100644 --- a/lib/rdoc/parser/c.rb +++ b/lib/rdoc/parser/c.rb @@ -239,7 +239,7 @@ def do_aliases 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) + add_alias(var_name, class_obj, old_name, new_name, comment, singleton: @singleton_classes.key?(var_name)) end end @@ -247,8 +247,8 @@ def do_aliases # 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, comment, singleton: @singleton_classes.key?(var_name) + def add_alias(var_name, class_obj, old_name, new_name, comment, singleton:) + al = RDoc::Alias.new old_name, new_name, comment, singleton: singleton al.record_location @top_level class_obj.add_alias al @stats.add_alias al @@ -987,7 +987,7 @@ def handle_ifdefs_in(body) def handle_method(type, var_name, meth_name, function, param_count, source_file = nil) class_name = @known_classes[var_name] - singleton = @singleton_classes.key? var_name + singleton = @singleton_classes.key?(var_name) || %w[singleton_method module_function].include?(type) @methods[var_name][function] << meth_name @@ -996,7 +996,7 @@ 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) + add_alias(var_name, class_obj, existing_method.name, meth_name, existing_method.comment, singleton: singleton) end if class_obj then @@ -1006,7 +1006,6 @@ def handle_method(type, var_name, meth_name, function, param_count, type = 'method' # force public end - singleton = singleton || %w[singleton_method module_function].include?(type) meth_obj = RDoc::AnyMethod.new meth_name, singleton: singleton meth_obj.c_function = function diff --git a/test/rdoc/parser/c_test.rb b/test/rdoc/parser/c_test.rb index 024f7644f6..2cef9b741a 100644 --- a/test/rdoc/parser/c_test.rb +++ b/test/rdoc/parser/c_test.rb @@ -218,7 +218,7 @@ def assert_do_attr(flags) end end - def test_do_aliases + def test_do_instance_define_alias content = <<~C /* * This should show up as an alias with documentation @@ -241,12 +241,39 @@ def test_do_aliases assert_equal 2, methods.length assert_equal 'bleh', methods.last.name assert_equal 'blah', methods.last.is_alias_for.name + refute methods.last.singleton assert_equal @top_level, methods.last.is_alias_for.file assert_equal @top_level, methods.last.file end - def test_do_aliases_singleton + def test_do_instance_duplicate_define_method + content = <<~C + VALUE blah(VALUE klass, VALUE year) { + } + + void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_method(cDate, "blah", blah, 1); + + rb_define_method(cDate, "bleh", blah, 1); + } + C + + klass = util_get_class content, 'cDate' + + methods = klass.method_list + assert_equal 2, methods.length + assert_equal 'bleh', methods.last.name + assert_equal 'blah', methods.last.is_alias_for.name + refute methods.last.singleton + + assert_equal @top_level, methods.last.is_alias_for.file + assert_equal @top_level, methods.last.file + end + + def test_do_singleton_define_alias content = <<~C /* * This should show up as a method with documentation @@ -278,6 +305,32 @@ def test_do_aliases_singleton assert_equal 'This should show up as an alias', methods.last.comment.text end + def test_do_singleton_duplicate_define_method + content = <<~C + VALUE blah(VALUE klass, VALUE year) { + } + + void Init_Blah(void) { + cDate = rb_define_class("Date", rb_cObject); + + rb_define_singleton_method(cDate, "blah", blah, 1); + + rb_define_singleton_method(cDate, "bleh", blah, 1); + } + C + + klass = util_get_class content, 'cDate' + + methods = klass.method_list + assert_equal 2, methods.length + assert_equal 'bleh', methods.last.name + assert methods.last.singleton + assert_equal 'blah', methods.last.is_alias_for.name + + assert_equal @top_level, methods.last.is_alias_for.file + assert_equal @top_level, methods.last.file + end + def test_do_aliases_missing_class content = <<~C void Init_Blah(void) {