Skip to content

Commit bc71285

Browse files
committed
Support constant assign parsed before class/module definition
Support `Const = RHS` parsed before `class RHS;end` defined in another file.
1 parent c77a277 commit bc71285

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

lib/rdoc/code_object/constant.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,18 @@ def is_alias_for
9292
@is_alias_for = found if found
9393
@is_alias_for
9494
else
95-
@is_alias_for
95+
@is_alias_for ||= find_alias_for
9696
end
9797
end
9898

99+
# Find alias constant for a value.
100+
# This is used when the constant is parsed before the class or module defined in another file.
101+
# Note that module nesting information is lost, so constant lookup is inaccurate.
102+
103+
def find_alias_for
104+
parent.find_module_named(value) if value&.match?(/\A(::)?([A-Z][A-Za-z0-9_]*)(::[A-Z][A-Za-z0-9_]*)*\z/)
105+
end
106+
99107
def inspect # :nodoc:
100108
"#<%s:0x%x %s::%s>" % [
101109
self.class, object_id,

lib/rdoc/code_object/context.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ def add_constant(constant)
439439
known.value = constant.value if
440440
known.value.nil? or known.value.strip.empty?
441441

442+
constant.parent = self
442443
known.is_alias_for ||= constant.is_alias_for
443444
else
444445
@constants_hash[constant.name] = constant

test/rdoc/parser/prism_ruby_test.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,50 @@ class Bar; end
16381638
assert_equal 'Foo::C', klass.find_module_named('C').full_name
16391639
end
16401640

1641+
def test_constant_alias_reverse_order
1642+
util_parser <<~RUBY
1643+
# Parsed first
1644+
class Foo
1645+
A = Bar
1646+
B = Foo::Bar
1647+
C = Baz
1648+
end
1649+
1650+
# Parsed later
1651+
class Foo
1652+
class Bar; end
1653+
end
1654+
class Baz; end
1655+
RUBY
1656+
klass = @top_level.classes.first
1657+
assert_equal 'Foo::Bar', klass.find_constant_named('A').is_alias_for.full_name
1658+
assert_equal 'Foo::Bar', klass.find_constant_named('B').is_alias_for.full_name
1659+
assert_equal 'Baz', klass.find_constant_named('C').is_alias_for.full_name
1660+
end
1661+
1662+
def test_repeated_constant_alias
1663+
util_parser <<~RUBY
1664+
# Parsed first
1665+
class Foo
1666+
if cond
1667+
A = Bar
1668+
B = Baz
1669+
else
1670+
A = Bar
1671+
B = Baz
1672+
end
1673+
end
1674+
1675+
# Parsed later
1676+
class Baz
1677+
end
1678+
RUBY
1679+
klass = @top_level.classes.first
1680+
assert_equal 'Bar', klass.find_constant_named('A').value
1681+
assert_nil klass.find_constant_named('A').is_alias_for
1682+
assert_equal 'Baz', klass.find_constant_named('B').is_alias_for.full_name
1683+
end
1684+
16411685
def test_constant_with_singleton_class
16421686
omit if accept_legacy_bug?
16431687
util_parser <<~RUBY

0 commit comments

Comments
 (0)