From 23018c2fb48ac7ada1ead79e3c896605c1b8bae6 Mon Sep 17 00:00:00 2001 From: tomoya ishida Date: Fri, 3 Jan 2025 20:13:52 +0900 Subject: [PATCH] [ruby/rdoc] Fix prism_ruby superclass resolve order (https://github.com/ruby/rdoc/pull/1267) RDoc::Parser::PrismRuby wrongly resolves superclass of `class Cipher < Cipher; end` that exist in openssl. Superclass resolve should be done before adding class. https://github.com/ruby/rdoc/commit/57a4615a92 --- lib/rdoc/parser/prism_ruby.rb | 6 ++++-- test/rdoc/test_rdoc_parser_prism_ruby.rb | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/rdoc/parser/prism_ruby.rb b/lib/rdoc/parser/prism_ruby.rb index 05e98ad6c4..06ef4abdb3 100644 --- a/lib/rdoc/parser/prism_ruby.rb +++ b/lib/rdoc/parser/prism_ruby.rb @@ -642,14 +642,16 @@ class RDoc::Parser::PrismRuby < RDoc::Parser owner, name = find_or_create_constant_owner_name(module_name) if is_class - mod = owner.classes_hash[name] || owner.add_class(RDoc::NormalClass, name, superclass_name || '::Object') - # RDoc::NormalClass resolves superclass name despite of the lack of module nesting information. # We need to fix it when RDoc::NormalClass resolved to a wrong constant name if superclass_name superclass_full_path = resolve_constant_path(superclass_name) superclass = @store.find_class_or_module(superclass_full_path) if superclass_full_path superclass_full_path ||= superclass_name + end + # add_class should be done after resolving superclass + mod = owner.classes_hash[name] || owner.add_class(RDoc::NormalClass, name, superclass_name || '::Object') + if superclass_name if superclass mod.superclass = superclass elsif mod.superclass.is_a?(String) && mod.superclass != superclass_full_path diff --git a/test/rdoc/test_rdoc_parser_prism_ruby.rb b/test/rdoc/test_rdoc_parser_prism_ruby.rb index 2ff11bb1a7..16b8d522b6 100644 --- a/test/rdoc/test_rdoc_parser_prism_ruby.rb +++ b/test/rdoc/test_rdoc_parser_prism_ruby.rb @@ -201,6 +201,25 @@ module RDocParserPrismTestCases assert_equal ['A::B', 'A::B', 'A::A::B', 'A::B'], classes.drop(1).map(&:superclass).map(&:full_name) end + def test_pseudo_recursive_superclass + util_parser <<~RUBY + module Foo + class Bar + class Foo < Bar; end + # This class definition is used in OpenSSL::Cipher::Cipher + class Bar < Bar; end + class Baz < Bar; end + end + end + RUBY + foo_klass = @store.find_class_named 'Foo::Bar::Foo' + bar_klass = @store.find_class_named 'Foo::Bar::Bar' + baz_klass = @store.find_class_named 'Foo::Bar::Baz' + assert_equal 'Foo::Bar', foo_klass.superclass.full_name + assert_equal 'Foo::Bar', bar_klass.superclass.full_name + assert_equal 'Foo::Bar::Bar', baz_klass.superclass.full_name + end + def test_class_module_nodoc util_parser <<~RUBY class Foo # :nodoc: