Skip to content

Fix Ruby parser to not create a class whose superclass references itself - #1784

Merged
tompng merged 1 commit into
ruby:masterfrom
tompng:fix_nil_superclass_case
Aug 24, 2026
Merged

Fix Ruby parser to not create a class whose superclass references itself#1784
tompng merged 1 commit into
ruby:masterfrom
tompng:fix_nil_superclass_case

Conversation

@tompng

@tompng tompng commented Aug 19, 2026

Copy link
Copy Markdown
Member

Fixes #1781

Context#add_class will create a class with nil superclass in some case: BasicObject, superclass referencing itself.
Ruby parser should support handling class with nil superclass, and also superclass overwrite mechanism should also follow this rule.

Context#add_class will create a class with nil superclass in some case: BasicObject, superclass referencing itself.
Ruby parser should support handling class with nil superclass, and also superclass overwrite mechanism should also follow this rule.
Copilot AI lite review requested due to automatic review settings August 19, 2026 06:44
@tompng
tompng requested a deployment to fork-preview-protection August 19, 2026 06:44 — with GitHub Actions Waiting

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the Prism-based Ruby parser’s class-superclass handling to avoid creating/overwriting superclasses in cases that should result in a nil superclass (notably BasicObject and self-referential superclass paths), preventing crashes when later code assumes a non-nil superclass object.

Changes:

  • Tighten superclass overwrite rules in RDoc::Parser::Ruby#add_module_or_class to avoid invalid/self-referential superclass assignments and tolerate nil superclasses.
  • Add a regression test covering BasicObject and self-superclass edge cases in Context#add_class / parser overwrite behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
lib/rdoc/parser/ruby.rb Updates superclass overwrite logic to avoid nil crashes and prevent invalid overwrites for BasicObject and self-referential superclass paths.
test/rdoc/parser/ruby_test.rb Adds coverage for nil superclass edge cases and (with suggested update) should include the #1781 nested-class repro.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/rdoc/parser/ruby.rb
if superclass
mod.superclass = superclass
elsif (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
elsif mod.superclass.nil? || (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
Comment thread lib/rdoc/parser/ruby.rb
Comment on lines +910 to +914
# Superclass with the same full path and superclass for BasicObject are not allowed
if superclass_name && mod.full_name != superclass_full_path && mod.full_name != 'BasicObject'
if superclass
mod.superclass = superclass
elsif (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
elsif mod.superclass.nil? || (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
Comment on lines +3026 to +3047
def test_nil_superclass_case
# Context#add_class will create a class with nil superclass when
# the class is a BasicObject, or a superclass has the same full_name as the class itself.
# Superclass overwrite should follow this rule.
util_parser <<~RUBY
class BasicObject < Super; end
class BasicObject < Super; end
class Foo < Foo; end
class Bar < Bar; end
class Bar < Super; end
module M
class Baz < Super; end
class Baz < Baz; end
class Baz < M::Baz; end
end
RUBY

assert_nil @store.find_class_named('BasicObject').superclass
assert_nil @store.find_class_named('Foo').superclass
assert_equal 'Super', @store.find_class_named('Bar').superclass
assert_equal 'Super', @store.find_class_named('M::Baz').superclass
end
@tompng
tompng merged commit a8b46ec into ruby:master Aug 24, 2026
28 of 29 checks passed
@tompng
tompng deleted the fix_nil_superclass_case branch August 24, 2026 18:14
tompng added a commit that referenced this pull request Aug 24, 2026
Related to #1781 and #1782
Fix crash when a class has a superclass cycle.

Superclass chain can have a cycle. Some cycle can be rejected in parse
phase(#1784), but I think some manually crafted case aren't possible to
reject in parse phase. So `ancestors` `superclasses` must handle cyclic
chain for now.

Even after #1784, superclass cycle can be created by:
```ruby
class A < B; end
class B < C; end
class C < B; end
```

(Perhaps there's an option to add validation phase that detects and
fixes cyclic chain in the future)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RDoc crashes when nested class inherits via superclass constant lookup

3 participants