Skip to content

RDoc crashes when nested class inherits via superclass constant lookup #1781

Description

@skatkov

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:

bundle install

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions