From a31e1e789918073deabaff90a542d7d99e3c262d Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sat, 29 Aug 2026 16:59:47 +0200 Subject: [PATCH 1/8] RBS cache during scan --- lib/rdoc/parser/rbs.rb | 44 ++++++++++++++-- test/rdoc/parser/rbs_test.rb | 97 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/lib/rdoc/parser/rbs.rb b/lib/rdoc/parser/rbs.rb index 107e6d0219..29dc60f680 100644 --- a/lib/rdoc/parser/rbs.rb +++ b/lib/rdoc/parser/rbs.rb @@ -11,6 +11,8 @@ class RDoc::Parser::RBS < RDoc::Parser parse_files_matching RBS_FILE_EXTENSION def scan + @attributes_by_context = {} + @methods_by_context = {} _, _, decls = ::RBS::Parser.parse_signature(@content) decls.each do |decl| parse_decl decl, @top_level @@ -90,12 +92,32 @@ def attr_rw_matches?(existing_rw, new_rw) existing_rw.each_char.any? { |rw| new_rw.include? rw } end + def attribute_index(context) + @attributes_by_context[context] ||= context.attributes.each_with_object({}) do |attribute, index| + index[[attribute.name, attribute.singleton]] ||= attribute + end + end + + def find_attribute(context, name, singleton) + attribute_index(context)[[name, singleton]] + end + + def method_index(context) + @methods_by_context[context] ||= context.method_list.each_with_object({}) do |method, index| + index[[method.name, !!method.singleton]] ||= method + end + end + + def find_method(context, name, singleton) + method_index(context)[[name, singleton]] + end + def merge_attribute_methods(context, name, rw, singleton, comment, type_signature_lines) method_names = [] 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| find_method(context, method_name, singleton) } methods.compact.each do |method| merge_documentation method, comment, type_signature_lines end @@ -135,7 +157,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 = find_attribute(context, name, singleton) merge_documentation attribute, comment, type_signature_lines if attr_rw_matches? attribute.rw, rw return @@ -154,7 +176,11 @@ def parse_attr_decl(decl, context) record_object_location attribute, decl.location attribute.type_signature_lines = type_signature_lines attribute.visibility = decl.visibility if decl.visibility + attribute_count = context.attributes.length context.add_attribute attribute + context.attributes[attribute_count..].each do |added_attribute| + attribute_index(context)[[added_attribute.name, added_attribute.singleton]] ||= added_attribute + end end def parse_class_decl(decl, context) @@ -235,7 +261,15 @@ def parse_method_alias_decl(decl, context) singleton: decl.kind == :singleton ) record_object_location alias_def, decl.location + method_count = context.method_list.length + attribute_count = context.attributes.length context.add_alias alias_def + context.method_list[method_count..].each do |method| + method_index(context)[[method.name, !!method.singleton]] ||= method + end + context.attributes[attribute_count..].each do |attribute| + attribute_index(context)[[attribute.name, attribute.singleton]] ||= attribute + end end def parse_method_decl(decl, context) @@ -245,7 +279,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 = find_method(context, method_name, singleton) merge_documentation method, comment, type_signature_lines return end @@ -261,7 +295,11 @@ def parse_method_decl(decl, context) method.comment = comment if comment method.visibility = visibility if visibility + method_count = context.method_list.length context.add_method method + context.method_list[method_count..].each do |added_method| + method_index(context)[[added_method.name, !!added_method.singleton]] ||= added_method + end end def parse_module_decl(decl, context) diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index 0365462cc1..d90b3d9ff1 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -143,6 +143,71 @@ 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_method_and_attribute_aliases + util_parser(<<~RBS).scan + class Sample + # Method alias docs. + alias salutation greet + alias display_name name + + def greet: () -> String + # Base attribute docs. + attr_reader name: String + + # Dedicated method docs. + def salutation: () -> String + # Dedicated attribute docs. + attr_reader display_name: String + end + RBS + + sample = @store.find_class_named 'Sample' + salutation = sample.find_method 'salutation', false + display_name = sample.find_attribute 'display_name', false + + assert_equal "Method alias docs.\n---\nDedicated method docs.", salutation.comment.to_s.strip + assert_equal "Base attribute docs.\n---\nDedicated attribute docs.", display_name.comment.to_s.strip + end + + def test_scan_treats_legacy_nil_singleton_as_instance_method + ruby_top_level = @store.add_file 'sample.rb' + sample = ruby_top_level.add_class RDoc::NormalClass, 'Sample' + greet = RDoc::AnyMethod.new 'greet' + greet.singleton = nil + sample.add_method greet + + util_parser(<<~RBS).scan + class Sample + def greet: () -> String + end + RBS + + assert_equal ['() -> String'], greet.type_signature_lines + 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' @@ -266,6 +331,38 @@ class PrivateSample assert_equal :public, private_constructor.visibility end + def test_scan_method_lookup_is_linear + name_calls = 0 + original_name = RDoc::AnyMethod.instance_method :name + RDoc::AnyMethod.define_method(:name) do + name_calls += 1 + original_name.bind_call self + end + + methods = 100.times.map { |i| " def m#{i}: () -> void" }.join("\n") + util_parser("class C\n#{methods}\nend\n").scan + + assert_operator name_calls, :<=, 1_000 + ensure + RDoc::AnyMethod.define_method :name, original_name + end + + def test_scan_attribute_lookup_is_linear + name_calls = 0 + original_name = RDoc::Attr.instance_method :name + RDoc::Attr.define_method(:name) do + name_calls += 1 + original_name.bind_call self + end + + attributes = 100.times.map { |i| " attr_reader a#{i}: String" }.join("\n") + util_parser("class C\n#{attributes}\nend\n").scan + + assert_operator name_calls, :<=, 1_000 + ensure + RDoc::Attr.remove_method :name + end + def util_parser(content) RDoc::Parser::RBS.new @top_level, content, @options, @stats end From 3b578179226b6d547bcfcd0af66653fa9140660a Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 14:20:02 +0200 Subject: [PATCH 2/8] Lazily update RBS member indexes Context#add_alias can append methods or attributes as a side effect, making mutation-side cache updates depend on Context internals. Index each collection's unconsumed tail during lookup instead, keeping synchronization in one place while preserving linear lookup. --- lib/rdoc/parser/rbs.rb | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/lib/rdoc/parser/rbs.rb b/lib/rdoc/parser/rbs.rb index 29dc60f680..2101456495 100644 --- a/lib/rdoc/parser/rbs.rb +++ b/lib/rdoc/parser/rbs.rb @@ -93,9 +93,11 @@ def attr_rw_matches?(existing_rw, new_rw) end def attribute_index(context) - @attributes_by_context[context] ||= context.attributes.each_with_object({}) do |attribute, index| + index = @attributes_by_context[context] ||= {} + context.attributes[index.length..].each do |attribute| index[[attribute.name, attribute.singleton]] ||= attribute end + index end def find_attribute(context, name, singleton) @@ -103,9 +105,11 @@ def find_attribute(context, name, singleton) end def method_index(context) - @methods_by_context[context] ||= context.method_list.each_with_object({}) do |method, index| + index = @methods_by_context[context] ||= {} + context.method_list[index.length..].each do |method| index[[method.name, !!method.singleton]] ||= method end + index end def find_method(context, name, singleton) @@ -176,11 +180,7 @@ def parse_attr_decl(decl, context) record_object_location attribute, decl.location attribute.type_signature_lines = type_signature_lines attribute.visibility = decl.visibility if decl.visibility - attribute_count = context.attributes.length context.add_attribute attribute - context.attributes[attribute_count..].each do |added_attribute| - attribute_index(context)[[added_attribute.name, added_attribute.singleton]] ||= added_attribute - end end def parse_class_decl(decl, context) @@ -261,15 +261,7 @@ def parse_method_alias_decl(decl, context) singleton: decl.kind == :singleton ) record_object_location alias_def, decl.location - method_count = context.method_list.length - attribute_count = context.attributes.length context.add_alias alias_def - context.method_list[method_count..].each do |method| - method_index(context)[[method.name, !!method.singleton]] ||= method - end - context.attributes[attribute_count..].each do |attribute| - attribute_index(context)[[attribute.name, attribute.singleton]] ||= attribute - end end def parse_method_decl(decl, context) @@ -295,11 +287,7 @@ def parse_method_decl(decl, context) method.comment = comment if comment method.visibility = visibility if visibility - method_count = context.method_list.length context.add_method method - context.method_list[method_count..].each do |added_method| - method_index(context)[[added_method.name, !!added_method.singleton]] ||= added_method - end end def parse_module_decl(decl, context) From 88028c633caa61586a34a1e5ad3ba406f5ee9f2e Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 14:43:46 +0200 Subject: [PATCH 3/8] remove method mocking tests --- test/rdoc/parser/rbs_test.rb | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index d90b3d9ff1..5199b61831 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -331,38 +331,6 @@ class PrivateSample assert_equal :public, private_constructor.visibility end - def test_scan_method_lookup_is_linear - name_calls = 0 - original_name = RDoc::AnyMethod.instance_method :name - RDoc::AnyMethod.define_method(:name) do - name_calls += 1 - original_name.bind_call self - end - - methods = 100.times.map { |i| " def m#{i}: () -> void" }.join("\n") - util_parser("class C\n#{methods}\nend\n").scan - - assert_operator name_calls, :<=, 1_000 - ensure - RDoc::AnyMethod.define_method :name, original_name - end - - def test_scan_attribute_lookup_is_linear - name_calls = 0 - original_name = RDoc::Attr.instance_method :name - RDoc::Attr.define_method(:name) do - name_calls += 1 - original_name.bind_call self - end - - attributes = 100.times.map { |i| " attr_reader a#{i}: String" }.join("\n") - util_parser("class C\n#{attributes}\nend\n").scan - - assert_operator name_calls, :<=, 1_000 - ensure - RDoc::Attr.remove_method :name - end - def util_parser(content) RDoc::Parser::RBS.new @top_level, content, @options, @stats end From 7e63a454c404da56edbb0ab1e42bca2bfe717fc9 Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 14:54:06 +0200 Subject: [PATCH 4/8] Revived both RBS linear-performance tests using assert_linear_performance --- test/rdoc/parser/rbs_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index 5199b61831..a94153ef70 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -331,6 +331,20 @@ class PrivateSample assert_equal :public, private_constructor.visibility end + def test_scan_method_lookup_linear_performance + assert_linear_performance([1, 10, 100]) do |factor| + methods = (factor * 200).times.map { |i| " def m#{i}: () -> void" }.join("\n") + util_parser("class C\n#{methods}\nend\n").scan + end + end + + def test_scan_attribute_lookup_linear_performance + assert_linear_performance([1, 10, 100]) do |factor| + attributes = (factor * 200).times.map { |i| " attr_reader a#{i}: String" }.join("\n") + util_parser("class C\n#{attributes}\nend\n").scan + end + end + def util_parser(content) RDoc::Parser::RBS.new @top_level, content, @options, @stats end From 558f2cc5b0fe535087e3441a7119569bee592596 Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 16:17:01 +0200 Subject: [PATCH 5/8] remove finder methods --- lib/rdoc/parser/rbs.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/rdoc/parser/rbs.rb b/lib/rdoc/parser/rbs.rb index 2101456495..c2421cf00c 100644 --- a/lib/rdoc/parser/rbs.rb +++ b/lib/rdoc/parser/rbs.rb @@ -100,10 +100,6 @@ def attribute_index(context) index end - def find_attribute(context, name, singleton) - attribute_index(context)[[name, singleton]] - end - def method_index(context) index = @methods_by_context[context] ||= {} context.method_list[index.length..].each do |method| @@ -112,16 +108,12 @@ def method_index(context) index end - def find_method(context, name, singleton) - method_index(context)[[name, singleton]] - end - def merge_attribute_methods(context, name, rw, singleton, comment, type_signature_lines) method_names = [] method_names << name if rw.include?('R') method_names << "#{name}=" if rw.include?('W') - methods = method_names.map { |method_name| find_method(context, method_name, singleton) } + methods = method_names.map { |method_name| method_index(context)[[method_name, singleton]] } methods.compact.each do |method| merge_documentation method, comment, type_signature_lines end @@ -161,7 +153,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 = find_attribute(context, name, singleton) + if attribute = attribute_index(context)[[name, singleton]] merge_documentation attribute, comment, type_signature_lines if attr_rw_matches? attribute.rw, rw return @@ -271,7 +263,7 @@ def parse_method_decl(decl, context) singleton = rdoc_method_singleton?(decl) visibility = rdoc_method_visibility(decl) - if method = find_method(context, method_name, singleton) + if method = method_index(context)[[method_name, singleton]] merge_documentation method, comment, type_signature_lines return end From 78a6b4ea5409bdfc0047e94d3440e2f4667c5b35 Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 16:17:15 +0200 Subject: [PATCH 6/8] simplify singleton setup --- test/rdoc/parser/rbs_test.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index a94153ef70..d8ddf29b9c 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -195,8 +195,7 @@ def salutation: () -> String def test_scan_treats_legacy_nil_singleton_as_instance_method ruby_top_level = @store.add_file 'sample.rb' sample = ruby_top_level.add_class RDoc::NormalClass, 'Sample' - greet = RDoc::AnyMethod.new 'greet' - greet.singleton = nil + greet = RDoc::AnyMethod.new 'greet', singleton: nil sample.add_method greet util_parser(<<~RBS).scan From e7f3e015e5fa86a5d2658594b906b7250bba784a Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Sun, 30 Aug 2026 16:17:25 +0200 Subject: [PATCH 7/8] combine two tests into one --- test/rdoc/parser/rbs_test.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index d8ddf29b9c..9f0a95fcd0 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -330,17 +330,10 @@ class PrivateSample assert_equal :public, private_constructor.visibility end - def test_scan_method_lookup_linear_performance + def test_scan_member_lookup_linear_performance assert_linear_performance([1, 10, 100]) do |factor| - methods = (factor * 200).times.map { |i| " def m#{i}: () -> void" }.join("\n") - util_parser("class C\n#{methods}\nend\n").scan - end - end - - def test_scan_attribute_lookup_linear_performance - assert_linear_performance([1, 10, 100]) do |factor| - attributes = (factor * 200).times.map { |i| " attr_reader a#{i}: String" }.join("\n") - util_parser("class C\n#{attributes}\nend\n").scan + 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 From 3c1659f3119f7cd0def99b354cbefa2ff3210fe3 Mon Sep 17 00:00:00 2001 From: "Stanislav (Stas) Katkov" Date: Tue, 1 Sep 2026 18:50:50 +0200 Subject: [PATCH 8/8] Use index from Context --- lib/rdoc/code_object/context.rb | 18 ++++++++++++++++-- lib/rdoc/parser/rbs.rb | 24 +++--------------------- test/rdoc/parser/rbs_test.rb | 24 +----------------------- test/rdoc/parser/ruby_test.rb | 7 +++++++ test/rdoc/rdoc_context_test.rb | 20 ++++++++++++++++++++ 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/lib/rdoc/code_object/context.rb b/lib/rdoc/code_object/context.rb index ccc9203141..da85909742 100644 --- a/lib/rdoc/code_object/context.rb +++ b/lib/rdoc/code_object/context.rb @@ -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 @@ -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 @@ -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 diff --git a/lib/rdoc/parser/rbs.rb b/lib/rdoc/parser/rbs.rb index c2421cf00c..ff3b68a43b 100644 --- a/lib/rdoc/parser/rbs.rb +++ b/lib/rdoc/parser/rbs.rb @@ -11,8 +11,6 @@ class RDoc::Parser::RBS < RDoc::Parser parse_files_matching RBS_FILE_EXTENSION def scan - @attributes_by_context = {} - @methods_by_context = {} _, _, decls = ::RBS::Parser.parse_signature(@content) decls.each do |decl| parse_decl decl, @top_level @@ -92,28 +90,12 @@ def attr_rw_matches?(existing_rw, new_rw) existing_rw.each_char.any? { |rw| new_rw.include? rw } end - def attribute_index(context) - index = @attributes_by_context[context] ||= {} - context.attributes[index.length..].each do |attribute| - index[[attribute.name, attribute.singleton]] ||= attribute - end - index - end - - def method_index(context) - index = @methods_by_context[context] ||= {} - context.method_list[index.length..].each do |method| - index[[method.name, !!method.singleton]] ||= method - end - index - end - def merge_attribute_methods(context, name, rw, singleton, comment, type_signature_lines) method_names = [] method_names << name if rw.include?('R') method_names << "#{name}=" if rw.include?('W') - methods = method_names.map { |method_name| method_index(context)[[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 @@ -153,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 = attribute_index(context)[[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 @@ -263,7 +245,7 @@ def parse_method_decl(decl, context) singleton = rdoc_method_singleton?(decl) visibility = rdoc_method_visibility(decl) - if method = method_index(context)[[method_name, singleton]] + if method = context.find_method_from_hash(method_name, singleton) merge_documentation method, comment, type_signature_lines return end diff --git a/test/rdoc/parser/rbs_test.rb b/test/rdoc/parser/rbs_test.rb index 9f0a95fcd0..7b22d26255 100644 --- a/test/rdoc/parser/rbs_test.rb +++ b/test/rdoc/parser/rbs_test.rb @@ -166,47 +166,25 @@ def name: () -> String assert_equal ['() -> String'], name.type_signature_lines end - def test_scan_indexes_forward_method_and_attribute_aliases + def test_scan_indexes_forward_attribute_alias util_parser(<<~RBS).scan class Sample - # Method alias docs. - alias salutation greet alias display_name name - def greet: () -> String # Base attribute docs. attr_reader name: String - # Dedicated method docs. - def salutation: () -> String # Dedicated attribute docs. attr_reader display_name: String end RBS sample = @store.find_class_named 'Sample' - salutation = sample.find_method 'salutation', false display_name = sample.find_attribute 'display_name', false - assert_equal "Method alias docs.\n---\nDedicated method docs.", salutation.comment.to_s.strip assert_equal "Base attribute docs.\n---\nDedicated attribute docs.", display_name.comment.to_s.strip end - def test_scan_treats_legacy_nil_singleton_as_instance_method - ruby_top_level = @store.add_file 'sample.rb' - sample = ruby_top_level.add_class RDoc::NormalClass, 'Sample' - greet = RDoc::AnyMethod.new 'greet', singleton: nil - sample.add_method greet - - util_parser(<<~RBS).scan - class Sample - def greet: () -> String - end - RBS - - assert_equal ['() -> String'], greet.type_signature_lines - 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' diff --git a/test/rdoc/parser/ruby_test.rb b/test/rdoc/parser/ruby_test.rb index 40cc6f4893..2020f9f715 100644 --- a/test/rdoc/parser/ruby_test.rb +++ b/test/rdoc/parser/ruby_test.rb @@ -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 diff --git a/test/rdoc/rdoc_context_test.rb b/test/rdoc/rdoc_context_test.rb index d193b324cd..ae54651f30 100644 --- a/test/rdoc/rdoc_context_test.rb +++ b/test/rdoc/rdoc_context_test.rb @@ -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') @@ -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