RDoc crashes with NoMethodError: undefined method 'name' for nil when parsing a valid nested class whose superclass is resolved through the containing class's inheritance chain.
Ruby executes the file correctly, but RDoc fails in RDoc::Parser::Ruby#add_module_or_class.
Reproduction
Create a clean directory with this Gemfile:
source "https://rubygems.org"
gem "rdoc", "8.0.0"
gem "prism", "1.9.0"
Create repro.rb:
module Example
class Base
class Connection
end
end
class Docker < Base
class Connection < Example::Docker::Connection
end
end
end
Install dependencies:
Verify that the Ruby is valid:
ruby -c repro.rb
ruby -I. -rrepro -e 'p Example::Docker::Connection.superclass'
Output:
Syntax OK
Example::Base::Connection
Run RDoc:
bundle exec rdoc --debug --force-output --output=doc repro.rb
Actual Behavior
RDoc crashes:
The internal error was:
(NoMethodError) undefined method 'name' for nil
rdoc-8.0.0/lib/rdoc/parser/ruby.rb:810:in `RDoc::Parser::Ruby#add_module_or_class'
rdoc-8.0.0/lib/rdoc/parser/ruby.rb:966:in `RDoc::Parser::Ruby::RDocVisitor#visit_class_node'
prism-1.9.0/lib/prism/node.rb:4085:in `Prism::ClassNode#accept'
The failing line in RDoc is:
elsif (mod.superclass.is_a?(String) || mod.superclass.name == "Object") &&
mod.superclass is nil in this case.
Expected Behavior
RDoc should generate documentation without crashing and record:
Example::Docker::Connection < Example::Base::Connection
If we switch to YARD, it can handle this case just fine.
Explanation
When Ruby evaluates:
class Connection < Example::Docker::Connection
the new Example::Docker::Connection constant has not yet been assigned. Constant lookup therefore finds the inherited Example::Base::Connection constant through Example::Docker < Example::Base.
RDoc appears not to handle this inherited constant lookup while constructing its class metadata.
Real-World Example
This occurs in the kitchen-docker gem, due to following code:
class Docker < Kitchen::Transport::Base
class Connection < Kitchen::Transport::Docker::Connection
end
end
Source: lib/kitchen/transport/docker.rb.
See here:
https://github.com/test-kitchen/kitchen-docker
RDoc crashes with
NoMethodError: undefined method 'name' for nilwhen parsing a valid nested class whose superclass is resolved through the containing class's inheritance chain.Ruby executes the file correctly, but RDoc fails in
RDoc::Parser::Ruby#add_module_or_class.Reproduction
Create a clean directory with this
Gemfile:Create
repro.rb:Install dependencies:
Verify that the Ruby is valid:
ruby -c repro.rb ruby -I. -rrepro -e 'p Example::Docker::Connection.superclass'Output:
Run RDoc:
bundle exec rdoc --debug --force-output --output=doc repro.rbActual Behavior
RDoc crashes:
The failing line in RDoc is:
mod.superclassisnilin this case.Expected Behavior
RDoc should generate documentation without crashing and record:
If we switch to YARD, it can handle this case just fine.
Explanation
When Ruby evaluates:
the new
Example::Docker::Connectionconstant has not yet been assigned. Constant lookup therefore finds the inheritedExample::Base::Connectionconstant throughExample::Docker < Example::Base.RDoc appears not to handle this inherited constant lookup while constructing its class metadata.
Real-World Example
This occurs in the
kitchen-dockergem, due to following code:Source:
lib/kitchen/transport/docker.rb.See here:
https://github.com/test-kitchen/kitchen-docker