Skip to content

Commit ab711b7

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 ab711b7

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

lib/rdoc/code_object/constant.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ def full_name
8686
# The module or class this constant is an alias for
8787

8888
def is_alias_for
89+
@is_alias_for ||= find_alias_for
90+
8991
case @is_alias_for
9092
when String then
9193
found = @store.find_class_or_module @is_alias_for
@@ -96,6 +98,14 @@ def is_alias_for
9698
end
9799
end
98100

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