You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stop lazy alias resolver from overwriting real classes
Fixes#1662.
PR #1621 made RDoc::Constant#is_alias_for fall through to a lazy
find_alias_for lookup that returned whatever class the constant's value
named in the current store. The lazy result then flowed into
RDoc::ClassModule#update_aliases, which unconditionally wrote a dup'd
alias copy into @store.classes_hash, with two safeguards present
elsewhere bypassed:
* Context#add_module_alias refuses to clobber an existing class entry
(the historic BasicObject = BlankSlate guard), but update_aliases
did not.
* The prism parser only registers an alias when the constant has
document_self set (so :nodoc: is honored), but the lazy resolver
ignored it.
In combination these meant `Foo = Bar # :nodoc:`, where a real `Foo`
class was parsed elsewhere, would silently replace the real class's
documentation with an alias copy of `Bar` -- the literal failure mode
in #1662 (the prism shim's `Ripper = Prism::Translation::Ripper`
clobbering the real Ripper class docs).
Architectural fix
-----------------
Split RDoc::Constant#is_alias_for back into a pure accessor and a
separate Constant#resolved_alias_target lookup. is_alias_for now
returns only what was recorded explicitly (by Context#add_module_alias,
by ClassModule#update_aliases, or by ri marshal load) and never mutates
state. resolved_alias_target is the opportunistic forward-reference
lookup, used only by update_aliases as a fallback when no explicit
alias is recorded; it honors document_self so :nodoc: constants
don't lazy-resolve.
The lazy lookup itself uses a new Constant#is_alias_for_path attribute
populated by the parsers, instead of regex-matching #value at lookup
time. Both the prism parser (via ConstantReadNode/ConstantPathNode
detection in constant_path_string) and the legacy ripper parser (via
on_const-only token accumulation in parse_constant_body) already know
whether the RHS is a constant reference at parse time; we now propagate
that explicitly rather than rediscovering it from a stringly-typed
value.
Mechanical fix
--------------
ClassModule#update_aliases falls back to const.resolved_alias_target
when const.is_alias_for is unset, and gates that lazy-resolved path
behind a collision check that mirrors the one in
Context#add_module_alias. Explicit aliases (already vetted by
add_module_alias) keep their existing path so the two compose.
Tests
-----
Parser-level regressions cover :nodoc: assignment, real-class
collision, the combined :nodoc:-plus-collision scenario from #1662,
and the :stopdoc:/:startdoc: workaround path. Each asserts both the
negative (the would-be alias didn't clobber) and the positive (the
alias target keeps its own methods and aliases list). Unit tests on
update_aliases assert the same. The two existing PR #1621 tests
(test_constant_alias_reverse_order, test_repeated_constant_alias) are
updated to exercise the renamed resolved_alias_target API; the
underlying forward-reference behavior is preserved.
0 commit comments