yard icon indicating copy to clipboard operation
yard copied to clipboard

Raise StackLevelTooDeep when defined cycle includes modules

Open HaiTo opened this issue 7 years ago • 3 comments

run yard doc *.rb and raise StackLevelTooDeep. As a result I can not get the documents.

Steps to reproduce

  1. define files ↓
# in one.rb
module One
  include Two
end

module Two
  include One
end
  1. run yard doc one.rb

  2. raise StackLevelTooDeep

Actual Output

$ yard doc one.rb --debug
[debug]: Parsing ["one.rb"] with `ruby` parser
[debug]: Parsing one.rb
[debug]: Serializing to .yardoc/objects/root.dat
[debug]: Re-generating object ...
[debug]: Re-generating object One...
[debug]: Re-generating object Two...
[debug]: Generating asset js/jquery.js
[debug]: Serializing to doc/js/jquery.js
[debug]: Generating asset js/app.js
[debug]: Serializing to doc/js/app.js
[debug]: Generating asset js/full_list.js
[debug]: Serializing to doc/js/full_list.js
[debug]: Generating asset css/style.css
[debug]: Serializing to doc/css/style.css
[debug]: Generating asset css/common.css
[debug]: Serializing to doc/css/common.css
[debug]: Generating asset css/full_list.css
[debug]: Serializing to doc/css/full_list.css
[debug]: Generating asset class_list.html
[debug]: Serializing to doc/class_list.html
[debug]: Generating asset method_list.html
[debug]: Serializing to doc/method_list.html
[debug]: Generating asset file_list.html
[debug]: Serializing to doc/file_list.html
[debug]: Generating asset frames.html
[debug]: Serializing to doc/frames.html
[debug]: Serializing to doc/index.html
[debug]: Serializing to doc/_index.html
[debug]: Serializing to doc/top-level-namespace.html
/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:132:in `hash': stack level too deep (SystemStackError)
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/namespace_object.rb:197:in `|'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/namespace_object.rb:197:in `mixins'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:17:in `block in inheritance_tree'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'
   ... 10684 levels...
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/command_parser.rb:54:in `run'
  from /Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/bin/yard:13:in `<top (required)>'
  from /Users/__my_rbenv_path__/versions/2.3.3/bin/yard:22:in `load'
  from /Users/__my_rbenv_path__/versions/2.3.3/bin/yard:22:in `<main>'

The omitted StackTrace is the following

Code for output

# in /Users/__my_rbenv_path__/versions/2.3.3/bin/yard

#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'yard' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0.a"

if ARGV.first
  str = ARGV.first
  str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
  if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
    version = $1
    ARGV.shift
  end
end
+ begin 
    load Gem.bin_path('yard', 'yard', version)
+ rescue SystemStackError => e
+   p e.backtrace
+ end

Actual

# omission ...
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/proxy.rb:175:in `method_missing'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:19:in `block in inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `map'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/code_objects/module_object.rb:14:in `inheritance_tree'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/module/setup.rb:96:in `inherited_constant_list'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/module/html/inherited_constants.erb:4:in `_erb_cache_19'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:287:in `erb'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:365:in `render_section'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:259:in `block (2 levels) in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `each'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `block in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:394:in `add_options'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:255:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:136:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:368:in `render_section'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:259:in `block (2 levels) in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `each'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `block in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:394:in `add_options'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:255:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:277:in `block in yieldall'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:408:in `with_section'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:277:in `yieldall'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/layout/html/layout.erb:21:in `_erb_cache_5'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:287:in `erb'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/layout/html/setup.rb:62:in `layout'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:363:in `render_section'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:259:in `block (2 levels) in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `each'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:256:in `block in run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:394:in `add_options'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:255:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:136:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/fulldoc/html/setup.rb:35:in `block in serialize'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/engine.rb:123:in `block in with_serializer'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/logging.rb:74:in `capture'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/engine.rb:121:in `with_serializer'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/fulldoc/html/setup.rb:34:in `serialize'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/fulldoc/html/setup.rb:19:in `block in init'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/fulldoc/html/setup.rb:17:in `each'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/templates/default/fulldoc/html/setup.rb:17:in `init'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:193:in `initialize'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:131:in `new'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/template.rb:136:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/templates/engine.rb:105:in `generate'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/yardoc.rb:349:in `run_generate'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/yardoc.rb:263:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/command.rb:14:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/command_parser.rb:72:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/lib/yard/cli/command_parser.rb:54:in `run'",
"/Users/__my_rbenv_path__/versions/2.3.3/lib/ruby/gems/2.3.0/gems/yard-0.9.9/bin/yard:13:in `<top (required)>'",
"/Users/__my_rbenv_path__/versions/2.3.3/bin/yard:22:in `load'",
"/Users/__my_rbenv_path__/versions/2.3.3/bin/yard:22:in `<main>'"

Expected Output

generate document

Environment details:

  • OS: [macOS Sierra version 10.12.2]
  • Ruby version (ruby -v): [ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]]
  • YARD version (yard -v): [yard 0.9.9]
  • Relevant software dependency/versions:

I have read the Contributing Guide.

HaiTo avatar Sep 01 '17 09:09 HaiTo

YARD should probably not crash, but this is invalid Ruby; you can't have cyclic includes anyway:

lib/one:10:in `append_features': cyclic include detected (ArgumentError)
        from lib/one.rb:10:in `include'
        from lib/one.rb:10:in `<module:Two>'
        from lib/one.rb:9:in `<main>'

lsegal avatar Sep 01 '17 18:09 lsegal

@lsegal thank you for reply. The sample code is the minimum case. I developing web applications using rails, I faced with the problem is the following code, which is actually the correct code for rails.

bad, Class and Module names are simplified

# in app/models/three.rb
class Three
  include One
end

# in app/models/concerns/one.rb
module One
  extend ActiveSupport::Concern
  include Two
end

# in app/models/concerns/two.rb
module Two
  include One
  extend ActiveSupport::Concern
end

However, I know that it is not easy to solve this problem. I am also forked the code of yard now and thinking a patch.. ✍️

thank you.

HaiTo avatar Sep 02 '17 13:09 HaiTo

@lsegal I coincidentally ran into this recently with a minimal case that is valid Ruby, due to a bug in YARD's name resolution:

module A
end

module A::Enumerable
  include Enumerable
end

This defines an A::Enumerable module that includes ::Enumerable, but YARD gets confused and constructs a cyclic mixins graph.

nelhage-stripe avatar Dec 21 '17 22:12 nelhage-stripe