Skip to content
Closed
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: 16 additions & 2 deletions lib/rdoc/code_object/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ def add(klass, name, comment)
def add_alias(an_alias)
return an_alias unless @document_self

method_attr = find_method(an_alias.old_name, an_alias.singleton) ||
find_attribute(an_alias.old_name, an_alias.singleton)
method_attr = find_method_from_hash(an_alias.old_name, an_alias.singleton) ||
find_attribute_from_hash(an_alias.old_name, an_alias.singleton)

if method_attr
method_attr.add_alias an_alias, self
Expand Down Expand Up @@ -749,6 +749,14 @@ def find_attribute(name, singleton)
@attributes.find { |a| a.name == name && a.singleton == singleton }
end

def find_attribute_from_hash(name, singleton) # :nodoc:
name = name.delete_suffix('=')
key = "#{singleton ? '::' : '#'}#{name}"
attribute = @methods_hash[key]
attribute = @methods_hash["#{key}="] unless RDoc::Attr === attribute
attribute if RDoc::Attr === attribute && attribute.singleton == singleton
end

##
# Finds an attribute with +name+ in this context

Expand Down Expand Up @@ -843,6 +851,12 @@ def find_method(name, singleton)
}
end

def find_method_from_hash(name, singleton) # :nodoc:
method = @methods_hash["#{singleton ? '::' : '#'}#{name}"]
# ponytail: keep the fallback until incremental rebuilds make this hash canonical.
RDoc::Attr === method ? find_method(name, singleton) : method
end

##
# Finds a instance or module method with +name+ in this context

Expand Down
6 changes: 3 additions & 3 deletions lib/rdoc/parser/rbs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def merge_attribute_methods(context, name, rw, singleton, comment, type_signatur
method_names << name if rw.include?('R')
method_names << "#{name}=" if rw.include?('W')

methods = method_names.map { |method_name| context.find_method(method_name, singleton) }
methods = method_names.map { |method_name| context.find_method_from_hash(method_name, singleton) }
methods.compact.each do |method|
merge_documentation method, comment, type_signature_lines
end
Expand Down Expand Up @@ -135,7 +135,7 @@ def parse_attr_decl(decl, context)
type_signature_lines = [decl.type.to_s]
name = decl.name.to_s
singleton = decl.kind == :singleton
if attribute = context.find_attribute(name, singleton)
if attribute = context.find_attribute_from_hash(name, singleton)
merge_documentation attribute, comment, type_signature_lines if
attr_rw_matches? attribute.rw, rw
return
Expand Down Expand Up @@ -245,7 +245,7 @@ def parse_method_decl(decl, context)
singleton = rdoc_method_singleton?(decl)
visibility = rdoc_method_visibility(decl)

if method = context.find_method(method_name, singleton)
if method = context.find_method_from_hash(method_name, singleton)
merge_documentation method, comment, type_signature_lines
return
end
Expand Down
49 changes: 49 additions & 0 deletions test/rdoc/parser/rbs_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,48 @@ def greet: () -> String
assert_equal ['() -> String'], greet.type_signature_lines
end

def test_scan_finds_existing_method_after_store_index_rebuild
ruby_top_level = @store.add_file 'sample.rb'
sample = ruby_top_level.add_class RDoc::NormalClass, 'Sample'

name = RDoc::AnyMethod.new 'name'
name.record_location ruby_top_level
sample.add_method name

name_writer = RDoc::Attr.new 'name', 'W', nil
name_writer.record_location ruby_top_level
sample.add_attribute name_writer

util_parser("class Sample\nend\n").scan
@store.clear_file_contributions @filename, keep_position: true
util_parser(<<~RBS).scan
class Sample
def name: () -> String
end
RBS

assert_equal ['() -> String'], name.type_signature_lines
end

def test_scan_indexes_forward_attribute_alias
util_parser(<<~RBS).scan
class Sample
alias display_name name

# Base attribute docs.
attr_reader name: String

# Dedicated attribute docs.
attr_reader display_name: String
end
RBS

sample = @store.find_class_named 'Sample'
display_name = sample.find_attribute 'display_name', false

assert_equal "Base attribute docs.\n---\nDedicated attribute docs.", display_name.comment.to_s.strip
end

def test_scan_preserves_rbs_markdown_when_extending_method_documentation
ruby_top_level = @store.add_file 'sample.rb'
sample = ruby_top_level.add_class RDoc::NormalClass, 'Sample'
Expand Down Expand Up @@ -266,6 +308,13 @@ class PrivateSample
assert_equal :public, private_constructor.visibility
end

def test_scan_member_lookup_linear_performance
assert_linear_performance([1, 10, 100]) do |factor|
members = Array.new(factor * 200) { |i| " def m#{i}: () -> void\n attr_reader a#{i}: String" }.join("\n")
util_parser("class C\n#{members}\nend\n").scan
end
end

def util_parser(content)
RDoc::Parser::RBS.new @top_level, content, @options, @stats
end
Expand Down
7 changes: 7 additions & 0 deletions test/rdoc/parser/ruby_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,13 @@ def test_read_directive_linear_performance
end
end

def test_alias_lookup_linear_performance
assert_linear_performance([1, 10, 100]) do |factor|
methods = Array.new(factor * 100) { |i| " def m#{i}; end\n alias a#{i} m#{i}" }.join("\n")
util_parser "class C#{factor}\n#{methods}\nend\n"
end
end

def test_code_object_token_stream
util_parser <<~RUBY
class Foo
Expand Down
20 changes: 20 additions & 0 deletions test/rdoc/rdoc_context_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,16 @@ def test_find_attribute_named
assert_equal 'RW', @c1.find_attribute_named('attr_accessor').rw
end

def test_find_attribute_from_hash
singleton = RDoc::Attr.new 'singleton', 'R', nil, singleton: true
@context.add_attribute singleton

assert_same @c1.find_attribute_named('attr_reader'), @c1.find_attribute_from_hash('attr_reader', false)
assert_same @c1.find_attribute_named('attr_writer'), @c1.find_attribute_from_hash('attr_writer=', false)
assert_same singleton, @context.find_attribute_from_hash('singleton', true)
assert_nil @c1.find_attribute_from_hash('attr_reader', true)
end

def test_find_class_method_named
assert_nil @c1.find_class_method_named('none')

Expand Down Expand Up @@ -584,6 +594,16 @@ def test_find_method
assert_equal @c2_b, loaded_c2.find_method('b', nil)
end

def test_find_method_from_hash
instance = RDoc::AnyMethod.new 'instance', singleton: nil
@context.add_method instance

assert_same instance, @context.find_method_from_hash('instance', false)
assert_same instance, @context.find_method_from_hash('instance', nil)
assert_same @c1__m, @c1.find_method_from_hash('m', true)
assert_nil @c1.find_method_from_hash('attr', false)
end

def test_find_method_named
assert_equal true, @c1.find_method_named('m').singleton
end
Expand Down