Skip to content

Commit 9e7ccd1

Browse files
committed
Fix broken sidebar links for chained class aliases
When Ruby defines chained aliases like `A = B = C` (e.g., `HTTPRequestURITooLarge = HTTPRequestURITooLong = HTTPURITooLong` in net/http), the sidebar link for the outermost alias pointed to the intermediate alias's HTML file, which is never generated. The root cause: `update_aliases` creates ClassModule objects whose `is_alias_for` references stale intermediate objects from `add_module_alias` that don't know they are aliases. Resolve through the store to follow already-processed aliases back to the real class. Also make `name_for_path` follow the alias chain recursively as a defensive measure. Fixes #1664.
1 parent 345c840 commit 9e7ccd1

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

lib/rdoc/code_object/class_module.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ def path
673673
# module or class return the name of the latter.
674674

675675
def name_for_path
676-
is_alias_for ? is_alias_for.full_name : full_name
676+
is_alias_for ? is_alias_for.name_for_path : full_name
677677
end
678678

679679
##
@@ -848,6 +848,11 @@ def type
848848
def update_aliases
849849
constants.each do |const|
850850
next unless cm = const.is_alias_for
851+
852+
# Resolve chained aliases (A = B = C) to the real class/module.
853+
cm = @store.find_class_or_module(cm.full_name) || cm
854+
cm = cm.is_alias_for while cm.is_alias_for
855+
851856
cm_alias = cm.dup
852857
cm_alias.name = const.name
853858

test/rdoc/generator/darkfish_test.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,43 @@ def test_canonical_url_for_classes
610610
assert_include(content, '<link rel="canonical" href="https://docs.ruby-lang.org/en/master/Klass/Inner.html">')
611611
end
612612

613+
def test_generate_chained_alias_sidebar_links
614+
# Reproduces ruby/rdoc#1664:
615+
# class Original < Base
616+
# DirectAlias = Original # alias of real class
617+
# ChainedAlias = DirectAlias # alias of an alias
618+
#
619+
# ChainedAlias's sidebar link must point to Original.html, not DirectAlias.html
620+
# (which is never generated because aliases don't get their own files).
621+
parent = @top_level.add_module RDoc::NormalModule, 'Parent'
622+
original = parent.add_class RDoc::NormalClass, 'Original'
623+
624+
direct_alias_const = RDoc::Constant.new 'DirectAlias', nil, ''
625+
direct_alias_const.record_location @top_level
626+
direct_alias_const.is_alias_for = original
627+
parent.add_constant direct_alias_const
628+
parent.update_aliases
629+
630+
direct_alias = @store.find_class_or_module 'Parent::DirectAlias'
631+
632+
chained_alias_const = RDoc::Constant.new 'ChainedAlias', nil, ''
633+
chained_alias_const.record_location @top_level
634+
chained_alias_const.is_alias_for = direct_alias
635+
parent.add_constant chained_alias_const
636+
parent.update_aliases
637+
638+
@store.complete :private
639+
@g.generate
640+
641+
assert_file 'Parent/Original.html'
642+
refute File.exist?('Parent/DirectAlias.html'), 'alias should not get its own file'
643+
refute File.exist?('Parent/ChainedAlias.html'), 'chained alias should not get its own file'
644+
645+
index_html = File.binread('index.html')
646+
assert_match %r{href="\./Parent/Original\.html">DirectAlias<}, index_html
647+
assert_match %r{href="\./Parent/Original\.html">ChainedAlias<}, index_html
648+
end
649+
613650
def test_canonical_url_for_rdoc_files
614651
@store.add_file("CONTRIBUTING.rdoc", parser: RDoc::Parser::Simple)
615652

0 commit comments

Comments
 (0)