Skip to content
Draft
Show file tree
Hide file tree
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
18 changes: 5 additions & 13 deletions lib/rdoc/code_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -291,19 +291,7 @@ def parent
return @parent if @parent
return nil unless @parent_name

if @parent_class == RDoc::TopLevel then
@parent = @store.add_file @parent_name
else
@parent = @store.find_class_or_module @parent_name

return @parent if @parent

begin
@parent = @store.load_class @parent_name
rescue RDoc::Store::MissingFileError
nil
end
end
@parent = @store&.resolve_parent(@parent_name, @parent_class)
end

##
Expand Down Expand Up @@ -361,6 +349,10 @@ def stop_doc
def store=(store)
@store = store

# When a CodeObject is loaded from Marshal data, its @file is a standalone
# TopLevel that needs to be replaced with the canonical one from the store.
@file = @store.add_file @file.full_name if @file && @store

return unless @track_visibility

if :nodoc == options.visibility then
Expand Down
9 changes: 0 additions & 9 deletions lib/rdoc/code_object/any_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,6 @@ def skip_description?
has_call_seq? && call_seq.nil? && !!(is_alias_for || !aliases.empty?)
end

##
# Sets the store for this method and its referenced code objects.

def store=(store)
super

@file = @store.add_file @file.full_name if @file
end

##
# For methods that +super+, find the superclass method that would be called.

Expand Down
8 changes: 4 additions & 4 deletions lib/rdoc/code_object/class_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,12 @@ def remove_nodoc_children

modules_hash.each_key do |name|
full_name = prefix + name
modules_hash.delete name unless @store.modules_hash[full_name]
modules_hash.delete name unless @store.find_module_named(full_name)
end

classes_hash.each_key do |name|
full_name = prefix + name
classes_hash.delete name unless @store.classes_hash[full_name]
classes_hash.delete name unless @store.find_class_named(full_name)
end
end

Expand Down Expand Up @@ -875,7 +875,7 @@ def update_aliases
def update_includes
includes.reject! do |include|
mod = include.module
!(String === mod) && @store.modules_hash[mod.full_name].nil?
!(String === mod) && @store.find_module_named(mod.full_name).nil?
end

includes.uniq!
Expand All @@ -891,7 +891,7 @@ def update_extends
extends.reject! do |ext|
mod = ext.module

!(String === mod) && @store.modules_hash[mod.full_name].nil?
!(String === mod) && @store.find_module_named(mod.full_name).nil?
end

extends.uniq!
Expand Down
9 changes: 0 additions & 9 deletions lib/rdoc/code_object/constant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,6 @@ def pretty_print(q) # :nodoc:
end
end

##
# Sets the store for this class or module and its contained code objects.

def store=(store)
super

@file = @store.add_file @file.full_name if @file
end

def to_s # :nodoc:
parent_name = parent ? parent.full_name : '(unknown)'
if is_alias_for
Expand Down
32 changes: 17 additions & 15 deletions lib/rdoc/code_object/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,11 @@ def add_class(class_type, given_name, superclass = '::Object')
if full_name =~ /^(.+)::(\w+)$/ then
name = $2
ename = $1
enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
enclosing = @store.find_class_or_module(ename)
# HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
unless enclosing then
# try the given name at top level (will work for the above example)
enclosing = @store.classes_hash[given_name] ||
@store.modules_hash[given_name]
enclosing = @store.find_class_or_module(given_name)
return enclosing if enclosing
# not found: create the parent(s)
names = ename.split('::')
Expand Down Expand Up @@ -358,7 +357,7 @@ def add_class(class_type, given_name, superclass = '::Object')
superclass = nil if superclass == full_name
end

klass = @store.classes_hash[full_name]
klass = @store.find_class_named(full_name)

if klass then
# if TopLevel, it may not be registered in the classes:
Expand All @@ -384,8 +383,7 @@ def add_class(class_type, given_name, superclass = '::Object')
else
klass = class_type.new name, superclass

enclosing.add_class_or_module(klass, enclosing.classes_hash,
@store.classes_hash)
enclosing.add_class_or_module(klass, enclosing.classes_hash)
end
end

Expand All @@ -395,13 +393,12 @@ def add_class(class_type, given_name, superclass = '::Object')
end

##
# Adds the class or module +mod+ to the modules or
# classes Hash +self_hash+, and to +all_hash+ (either
# <tt>TopLevel::modules_hash</tt> or <tt>TopLevel::classes_hash</tt>),
# Adds the class or module +mod+ to the local Hash +self_hash+,
# and registers it with the store,
# unless #done_documenting is +true+. Sets the #parent of +mod+
# to +self+, and its #section to #current_section. Returns +mod+.

def add_class_or_module(mod, self_hash, all_hash)
def add_class_or_module(mod, self_hash)
mod.section = current_section # TODO declaring context? something is
# wrong here...
mod.parent = self
Expand All @@ -412,7 +409,11 @@ def add_class_or_module(mod, self_hash, all_hash)
self_hash[mod.name] = mod
# this must be done AFTER adding mod to its parent, so that the full
# name is correct:
all_hash[mod.full_name] = mod
if mod.module? then
@store.modules_hash[mod.full_name] = mod
else
@store.classes_hash[mod.full_name] = mod
end
if @store.unmatched_constant_alias[mod.full_name] then
to, file = @store.unmatched_constant_alias[mod.full_name]
add_module_alias mod, mod.name, to, file
Expand Down Expand Up @@ -508,16 +509,16 @@ def add_module(class_type, name)
return mod if mod

full_name = child_name name
mod = @store.modules_hash[full_name] || class_type.new(name)
mod = @store.find_module_named(full_name) || class_type.new(name)

add_class_or_module mod, @modules, @store.modules_hash
add_class_or_module mod, @modules
end

##
# Adds a module by +RDoc::NormalModule+ instance. See also #add_module.

def add_module_by_normal_module(mod)
add_class_or_module mod, @modules, @store.modules_hash
add_class_or_module mod, @modules
end

##
Expand Down Expand Up @@ -1222,8 +1223,9 @@ def upgrade_to_class(mod, class_type, enclosing)
klass.store = @store

# if it was there, then we keep it even if done_documenting
@store.modules_hash.delete mod.full_name
@store.classes_hash[mod.full_name] = klass
enclosing.classes_hash[mod.name] = klass
enclosing.classes_hash[mod.name] = klass

klass
end
Expand Down
11 changes: 1 addition & 10 deletions lib/rdoc/code_object/method_attr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,6 @@ def see
@see
end

##
# Sets the store for this class or module and its contained code objects.

def store=(store)
super

@file = @store.add_file @file.full_name if @file
end

def find_see # :nodoc:
return nil if singleton || is_alias_for

Expand All @@ -172,7 +163,7 @@ def find_method_or_attribute(name) # :nodoc:
return nil unless parent.respond_to? :ancestors

searched = parent.ancestors
kernel = @store.modules_hash['Kernel']
kernel = @store.find_module_named('Kernel')

searched << kernel if kernel &&
parent != kernel && !searched.include?(kernel)
Expand Down
36 changes: 1 addition & 35 deletions lib/rdoc/code_object/mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,43 +77,9 @@ def inspect # :nodoc:

def module
return @module if @module

# search the current context
return @name unless parent
full_name = parent.child_name(@name)
@module = @store.modules_hash[full_name]
return @module if @module
return @name if @name =~ /^::/

# search the includes before this one, in reverse order
searched = parent.includes.take_while { |i| i != self }.reverse
searched.each do |i|
inc = i.module
next if String === inc
full_name = inc.child_name(@name)
@module = @store.modules_hash[full_name]
return @module if @module
end

# go up the hierarchy of names
up = parent.parent
while up
full_name = up.child_name(@name)
@module = @store.modules_hash[full_name]
return @module if @module
up = up.parent
end

@name
end

##
# Sets the store for this class or module and its contained code objects.

def store=(store)
super

@file = @store.add_file @file.full_name if @file
@module = @store&.resolve_mixin(@name, parent, self) || @name
end

def to_s # :nodoc:
Expand Down
57 changes: 57 additions & 0 deletions lib/rdoc/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,63 @@ def modules_hash
@modules_hash
end

##
# Resolves a parent CodeObject by +parent_name+ and +parent_class+.
# This encapsulates the lazy parent resolution logic: if the parent is a
# TopLevel, it is resolved via add_file; otherwise it is looked up in the
# class/module registry, falling back to loading from disk.

def resolve_parent(parent_name, parent_class)
if parent_class == RDoc::TopLevel
add_file parent_name
else
find_class_or_module(parent_name) || begin
load_class(parent_name)
rescue MissingFileError
nil
end
end
end

##
# Resolves a mixin's module reference by walking the namespace hierarchy.
# +name+ is the module name to resolve, +parent_context+ is the Context
# containing the mixin, and +mixin+ is the Mixin object itself (used to
# limit the include search to only includes before this one).
#
# Returns the resolved RDoc::NormalModule, or nil if not found.

def resolve_mixin(name, parent_context, mixin)
return nil unless parent_context

# search the current context
full_name = parent_context.child_name(name)
found = find_module_named(full_name)
return found if found
return nil if name =~ /^::/

# search the includes before this one, in reverse order
searched = parent_context.includes.take_while { |i| i != mixin }.reverse
searched.each do |i|
inc = i.module
next if String === inc
full_name = inc.child_name(name)
found = find_module_named(full_name)
return found if found
end

# go up the hierarchy of names
up = parent_context.parent
while up
full_name = up.child_name(name)
found = find_module_named(full_name)
return found if found
up = up.parent
end

nil
end

##
# Returns the RDoc::TopLevel that is a file and has the given +name+

Expand Down
4 changes: 2 additions & 2 deletions test/rdoc/parser/ruby_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2016,8 +2016,8 @@ def test_parse_method_constant

@parser.parse_method m, RDoc::Parser::Ruby::NORMAL, tk, @comment

assert_empty @store.modules_hash.keys
assert_equal %w[M], @store.classes_hash.keys
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test was wrong: if M is added as a NormalModule, it should appear in the modules hash, not classes hash.

assert_equal %w[M], @store.modules_hash.keys
assert_empty @store.classes_hash.keys
end

def test_parse_method_false
Expand Down