diff --git a/lib/rdoc/code_object/context.rb b/lib/rdoc/code_object/context.rb index 3a4dd0ec68..3ebcaba76b 100644 --- a/lib/rdoc/code_object/context.rb +++ b/lib/rdoc/code_object/context.rb @@ -785,7 +785,8 @@ def find_constant_named(name) end ## - # Find a module at a higher scope + # Tries to find a module at a higher scope. + # But parent is not always a higher module nesting scope, so the result is not correct. def find_enclosing_module_named(name) parent && parent.find_module_named(name) @@ -860,7 +861,8 @@ def find_method_named(name) end ## - # Find a module with +name+ using ruby's scoping rules + # Find a module with +name+ trying to using ruby's scoping rules. + # find_enclosing_module_named cannot use ruby's scoping so the result is not correct. def find_module_named(name) res = @modules[name] || @classes[name] @@ -869,6 +871,13 @@ def find_module_named(name) find_enclosing_module_named name end + # Get a module named +name+ in this context + # Don't look up for higher module nesting scopes. RDoc::Context doesn't have that information. + + def get_module_named(name) + @modules[name] || @classes[name] + end + ## # Look up +symbol+, first as a module, then as a local symbol. diff --git a/lib/rdoc/code_object/mixin.rb b/lib/rdoc/code_object/mixin.rb index 9b425efd2e..e7b37e0941 100644 --- a/lib/rdoc/code_object/mixin.rb +++ b/lib/rdoc/code_object/mixin.rb @@ -71,6 +71,9 @@ def inspect # :nodoc: # lookup behavior. # # As of the beginning of October, 2011, no gem includes nonexistent modules. + # + # When mixin is created from RDoc::Parser::PrismRuby, module name is already a resolved full-path name. + # def module return @module if @module diff --git a/lib/rdoc/code_object/top_level.rb b/lib/rdoc/code_object/top_level.rb index 553f45884c..21e412f82a 100644 --- a/lib/rdoc/code_object/top_level.rb +++ b/lib/rdoc/code_object/top_level.rb @@ -149,6 +149,8 @@ def find_module_named(name) find_class_or_module(name) end + alias get_module_named find_module_named + ## # Returns the relative name of this file diff --git a/lib/rdoc/parser/prism_ruby.rb b/lib/rdoc/parser/prism_ruby.rb index 56da6ac227..877b6045b2 100644 --- a/lib/rdoc/parser/prism_ruby.rb +++ b/lib/rdoc/parser/prism_ruby.rb @@ -59,11 +59,6 @@ def with_container(container, singleton: false) @container = container @singleton = singleton @in_proc_block = false - unless singleton - # Need to update module parent chain to emulate Module.nesting. - # This mechanism is inaccurate and needs to be fixed. - container.parent = old_container - end @module_nesting.push([container, singleton]) yield container ensure @@ -482,12 +477,15 @@ def add_attributes(names, rw, line_no) end end + # Adds includes/extends. Module name is resolved to full before adding. + def add_includes_extends(names, rdoc_class, line_no) # :nodoc: return if @in_proc_block comment, directives = consecutive_comment(line_no) handle_code_object_directives(@container, directives) if directives names.each do |name| - ie = @container.add(rdoc_class, name, '') + resolved_name = resolve_constant_path(name) + ie = @container.add(rdoc_class, resolved_name || name, '') ie.store = @store ie.line = line_no ie.comment = comment @@ -590,7 +588,7 @@ def find_or_create_module_path(module_name, create_mode) else @module_nesting.reverse_each do |nesting, singleton| next if singleton - mod = nesting.find_module_named(root_name) + mod = nesting.get_module_named(root_name) break if mod # If a constant is found and it is not a module or class, RDoc can't document about it. # Return an anonymous module to avoid wrong document creation. @@ -601,9 +599,9 @@ def find_or_create_module_path(module_name, create_mode) mod ||= add_module.call(last_nesting, root_name, :module) end path.each do |name| - mod = mod.find_module_named(name) || add_module.call(mod, name, :module) + mod = mod.get_module_named(name) || add_module.call(mod, name, :module) end - mod.find_module_named(name) || add_module.call(mod, name, create_mode) + mod.get_module_named(name) || add_module.call(mod, name, create_mode) end # Resolves constant path to a full path by searching module nesting @@ -614,10 +612,10 @@ def resolve_constant_path(constant_path) mod = nil @module_nesting.reverse_each do |nesting, singleton| next if singleton - mod = nesting.find_module_named(owner_name) + mod = nesting.get_module_named(owner_name) break if mod end - mod ||= @top_level.find_module_named(owner_name) + mod ||= @top_level.get_module_named(owner_name) [mod.full_name, path].compact.join('::') if mod end @@ -657,7 +655,8 @@ def add_constant(constant_name, rhs_name, start_line, end_line) if rhs_name =~ /^::/ @store.find_class_or_module(rhs_name) else - @container.find_module_named(rhs_name) + full_name = resolve_constant_path(rhs_name) + @store.find_class_or_module(full_name) end if mod && constant.document_self a = @container.add_module_alias(mod, rhs_name, constant, @top_level) diff --git a/test/rdoc/parser/prism_ruby_test.rb b/test/rdoc/parser/prism_ruby_test.rb index e393f70e3e..26be342ecb 100644 --- a/test/rdoc/parser/prism_ruby_test.rb +++ b/test/rdoc/parser/prism_ruby_test.rb @@ -1746,6 +1746,7 @@ class << self end def test_include_with_module_nesting + omit 'not implemented' if accept_legacy_bug? util_parser <<~RUBY module A module M; end @@ -1765,15 +1766,16 @@ class C::D::Foo include M end end - # TODO: make test pass with the following code appended - # module A::B::C - # class D::Foo - # include M - # end - # end + + module A::B::C + class D::Foo + include M + end + end RUBY klass = @store.find_class_named 'A::B::C::D::Foo' - assert_equal 'A::B::M', klass.includes.first.module.full_name + assert_equal 'A::B::M', klass.includes[0].module.full_name + assert_equal 'A::B::C::M', klass.includes[1].module.full_name end def test_various_argument_include