rdoc 7.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -4
  3. data/LICENSE.rdoc +4 -0
  4. data/README.md +43 -2
  5. data/doc/markup_reference/markdown.md +104 -3
  6. data/lib/rdoc/code_object/alias.rb +2 -8
  7. data/lib/rdoc/code_object/any_method.rb +11 -6
  8. data/lib/rdoc/code_object/attr.rb +11 -6
  9. data/lib/rdoc/code_object/class_module.rb +62 -32
  10. data/lib/rdoc/code_object/constant.rb +29 -3
  11. data/lib/rdoc/code_object/context/section.rb +4 -35
  12. data/lib/rdoc/code_object/context.rb +39 -34
  13. data/lib/rdoc/code_object/method_attr.rb +9 -15
  14. data/lib/rdoc/code_object/mixin.rb +2 -2
  15. data/lib/rdoc/code_object/top_level.rb +9 -3
  16. data/lib/rdoc/code_object.rb +2 -4
  17. data/lib/rdoc/comment.rb +0 -65
  18. data/lib/rdoc/cross_reference.rb +7 -27
  19. data/lib/rdoc/encoding.rb +3 -3
  20. data/lib/rdoc/generator/aliki.rb +17 -0
  21. data/lib/rdoc/generator/darkfish.rb +12 -6
  22. data/lib/rdoc/generator/json_index.rb +2 -2
  23. data/lib/rdoc/generator/markup.rb +56 -31
  24. data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
  25. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  26. data/lib/rdoc/generator/template/aliki/_head.rhtml +1 -1
  27. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  28. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  29. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  30. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
  31. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  32. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  33. data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
  34. data/lib/rdoc/generator/template/aliki/css/rdoc.css +337 -111
  35. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  36. data/lib/rdoc/generator/template/aliki/js/aliki.js +20 -18
  37. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  38. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  39. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  40. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  41. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  42. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  43. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  46. data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
  47. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
  48. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  49. data/lib/rdoc/i18n/text.rb +3 -3
  50. data/lib/rdoc/markdown.kpeg +15 -10
  51. data/lib/rdoc/markdown.rb +289 -104
  52. data/lib/rdoc/markup/document.rb +2 -2
  53. data/lib/rdoc/markup/formatter.rb +24 -34
  54. data/lib/rdoc/markup/heading.rb +1 -4
  55. data/lib/rdoc/markup/indented_paragraph.rb +1 -1
  56. data/lib/rdoc/markup/list.rb +2 -2
  57. data/lib/rdoc/markup/list_item.rb +2 -2
  58. data/lib/rdoc/markup/pre_process.rb +0 -25
  59. data/lib/rdoc/markup/to_ansi.rb +1 -1
  60. data/lib/rdoc/markup/to_bs.rb +1 -1
  61. data/lib/rdoc/markup/to_html.rb +131 -53
  62. data/lib/rdoc/markup/to_html_crossref.rb +97 -71
  63. data/lib/rdoc/markup/to_html_snippet.rb +5 -5
  64. data/lib/rdoc/markup/to_joined_paragraph.rb +0 -5
  65. data/lib/rdoc/markup/to_label.rb +2 -2
  66. data/lib/rdoc/markup/to_markdown.rb +1 -1
  67. data/lib/rdoc/markup/to_rdoc.rb +2 -2
  68. data/lib/rdoc/markup/to_table_of_contents.rb +1 -1
  69. data/lib/rdoc/markup/to_tt_only.rb +0 -7
  70. data/lib/rdoc/markup/verbatim.rb +1 -1
  71. data/lib/rdoc/options.rb +36 -51
  72. data/lib/rdoc/parser/c.rb +7 -6
  73. data/lib/rdoc/parser/rbs.rb +275 -0
  74. data/lib/rdoc/parser/ruby.rb +954 -2066
  75. data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
  76. data/lib/rdoc/parser.rb +3 -2
  77. data/lib/rdoc/rbs_helper.rb +186 -0
  78. data/lib/rdoc/rdoc.rb +196 -24
  79. data/lib/rdoc/ri/driver.rb +8 -2
  80. data/lib/rdoc/ri/paths.rb +1 -1
  81. data/lib/rdoc/{servlet.rb → ri/servlet.rb} +5 -5
  82. data/lib/rdoc/ri.rb +4 -3
  83. data/lib/rdoc/rubygems_hook.rb +11 -11
  84. data/lib/rdoc/server.rb +460 -0
  85. data/lib/rdoc/stats.rb +147 -124
  86. data/lib/rdoc/store.rb +212 -4
  87. data/lib/rdoc/task.rb +16 -15
  88. data/lib/rdoc/text.rb +1 -118
  89. data/lib/rdoc/token_stream.rb +11 -33
  90. data/lib/rdoc/version.rb +1 -1
  91. data/lib/rdoc.rb +35 -7
  92. data/lib/rubygems_plugin.rb +2 -11
  93. data/rdoc-logo.svg +43 -0
  94. data/rdoc.gemspec +6 -4
  95. metadata +35 -18
  96. data/lib/rdoc/code_object/anon_class.rb +0 -10
  97. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  98. data/lib/rdoc/code_object/meta_method.rb +0 -6
  99. data/lib/rdoc/parser/prism_ruby.rb +0 -1112
  100. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  101. data/lib/rdoc/parser/ruby_tools.rb +0 -163
@@ -1,1112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'prism'
4
- require_relative 'ripper_state_lex'
5
-
6
- # Unlike lib/rdoc/parser/ruby.rb, this file is not based on rtags and does not contain code from
7
- # rtags.rb -
8
- # ruby-lex.rb - ruby lexcal analyzer
9
- # ruby-token.rb - ruby tokens
10
-
11
- # Parse and collect document from Ruby source code.
12
- # RDoc::Parser::PrismRuby is compatible with RDoc::Parser::Ruby and aims to replace it.
13
-
14
- class RDoc::Parser::PrismRuby < RDoc::Parser
15
-
16
- parse_files_matching(/\.rbw?$/) if ENV['RDOC_USE_PRISM_PARSER']
17
-
18
- attr_accessor :visibility
19
- attr_reader :container, :singleton, :in_proc_block
20
-
21
- def initialize(top_level, content, options, stats)
22
- super
23
-
24
- content = handle_tab_width(content)
25
-
26
- @size = 0
27
- @token_listeners = nil
28
- content = RDoc::Encoding.remove_magic_comment content
29
- @content = content
30
- @markup = @options.markup
31
- @track_visibility = :nodoc != @options.visibility
32
- @encoding = @options.encoding
33
-
34
- @module_nesting = [[top_level, false]]
35
- @container = top_level
36
- @visibility = :public
37
- @singleton = false
38
- @in_proc_block = false
39
- end
40
-
41
- # Suppress `extend` and `include` within block
42
- # because they might be a metaprogramming block
43
- # example: `Module.new { include M }` `M.module_eval { include N }`
44
-
45
- def with_in_proc_block
46
- in_proc_block = @in_proc_block
47
- @in_proc_block = true
48
- yield
49
- @in_proc_block = in_proc_block
50
- end
51
-
52
- # Dive into another container
53
-
54
- def with_container(container, singleton: false)
55
- old_container = @container
56
- old_visibility = @visibility
57
- old_singleton = @singleton
58
- old_in_proc_block = @in_proc_block
59
- @visibility = :public
60
- @container = container
61
- @singleton = singleton
62
- @in_proc_block = false
63
- @module_nesting.push([container, singleton])
64
- yield container
65
- ensure
66
- @container = old_container
67
- @visibility = old_visibility
68
- @singleton = old_singleton
69
- @in_proc_block = old_in_proc_block
70
- @module_nesting.pop
71
- end
72
-
73
- # Records the location of this +container+ in the file for this parser and
74
- # adds it to the list of classes and modules in the file.
75
-
76
- def record_location(container) # :nodoc:
77
- case container
78
- when RDoc::ClassModule then
79
- @top_level.add_to_classes_or_modules container
80
- end
81
-
82
- container.record_location @top_level
83
- end
84
-
85
- # Scans this Ruby file for Ruby constructs
86
-
87
- def scan
88
- @tokens = RDoc::Parser::RipperStateLex.parse(@content)
89
- @lines = @content.lines
90
- result = Prism.parse(@content)
91
- @program_node = result.value
92
- @line_nodes = {}
93
- prepare_line_nodes(@program_node)
94
- prepare_comments(result.comments)
95
- return if @top_level.done_documenting
96
-
97
- @first_non_meta_comment_start_line = nil
98
- if (_line_no, start_line = @unprocessed_comments.first)
99
- @first_non_meta_comment_start_line = start_line if start_line < @program_node.location.start_line
100
- end
101
-
102
- @program_node.accept(RDocVisitor.new(self, @top_level, @store))
103
- process_comments_until(@lines.size + 1)
104
- end
105
-
106
- def should_document?(code_object) # :nodoc:
107
- return true unless @track_visibility
108
- return false if code_object.parent&.document_children == false
109
- code_object.document_self
110
- end
111
-
112
- # Assign AST node to a line.
113
- # This is used to show meta-method source code in the documentation.
114
-
115
- def prepare_line_nodes(node) # :nodoc:
116
- case node
117
- when Prism::CallNode, Prism::DefNode
118
- @line_nodes[node.location.start_line] ||= node
119
- end
120
- node.compact_child_nodes.each do |child|
121
- prepare_line_nodes(child)
122
- end
123
- end
124
-
125
- # Prepares comments for processing. Comments are grouped into consecutive.
126
- # Consecutive comment is linked to the next non-blank line.
127
- #
128
- # Example:
129
- # 01| class A # modifier comment 1
130
- # 02| def foo; end # modifier comment 2
131
- # 03|
132
- # 04| # consecutive comment 1 start_line: 4
133
- # 05| # consecutive comment 1 linked to line: 7
134
- # 06|
135
- # 07| # consecutive comment 2 start_line: 7
136
- # 08| # consecutive comment 2 linked to line: 10
137
- # 09|
138
- # 10| def bar; end # consecutive comment 2 linked to this line
139
- # 11| end
140
-
141
- def prepare_comments(comments)
142
- current = []
143
- consecutive_comments = [current]
144
- @modifier_comments = {}
145
- comments.each do |comment|
146
- if comment.is_a? Prism::EmbDocComment
147
- consecutive_comments << [comment] << (current = [])
148
- elsif comment.location.start_line_slice.match?(/\S/)
149
- text = comment.slice
150
- text = RDoc::Encoding.change_encoding(text, @encoding) if @encoding
151
- @modifier_comments[comment.location.start_line] = text
152
- elsif current.empty? || current.last.location.end_line + 1 == comment.location.start_line
153
- current << comment
154
- else
155
- consecutive_comments << (current = [comment])
156
- end
157
- end
158
- consecutive_comments.reject!(&:empty?)
159
-
160
- # Example: line_no = 5, start_line = 2, comment_text = "# comment_start_line\n# comment\n"
161
- # 1| class A
162
- # 2| # comment_start_line
163
- # 3| # comment
164
- # 4|
165
- # 5| def f; end # comment linked to this line
166
- # 6| end
167
- @unprocessed_comments = consecutive_comments.map! do |comments|
168
- start_line = comments.first.location.start_line
169
- line_no = comments.last.location.end_line + (comments.last.location.end_column == 0 ? 0 : 1)
170
- texts = comments.map do |c|
171
- c.is_a?(Prism::EmbDocComment) ? c.slice.lines[1...-1].join : c.slice
172
- end
173
- text = texts.join("\n")
174
- text = RDoc::Encoding.change_encoding(text, @encoding) if @encoding
175
- line_no += 1 while @lines[line_no - 1]&.match?(/\A\s*$/)
176
- [line_no, start_line, text]
177
- end
178
-
179
- # The first comment is special. It defines markup for the rest of the comments.
180
- _, first_comment_start_line, first_comment_text = @unprocessed_comments.first
181
- if first_comment_text && @lines[0...first_comment_start_line - 1].all? { |l| l.match?(/\A\s*$/) }
182
- _text, directives = @preprocess.parse_comment(first_comment_text, first_comment_start_line, :ruby)
183
- markup, = directives['markup']
184
- @markup = markup.downcase if markup
185
- end
186
- end
187
-
188
- # Creates an RDoc::Method on +container+ from +comment+ if there is a
189
- # Signature section in the comment
190
-
191
- def parse_comment_tomdoc(container, comment, line_no, start_line)
192
- return unless signature = RDoc::TomDoc.signature(comment)
193
-
194
- name, = signature.split %r%[ \(]%, 2
195
-
196
- meth = RDoc::GhostMethod.new comment.text, name
197
- record_location(meth)
198
- meth.line = start_line
199
- meth.call_seq = signature
200
- return unless meth.name
201
-
202
- meth.start_collecting_tokens(:ruby)
203
- node = @line_nodes[line_no]
204
- tokens = node ? visible_tokens_from_location(node.location) : [file_line_comment_token(start_line)]
205
- tokens.each { |token| meth.token_stream << token }
206
-
207
- container.add_method meth
208
- meth.comment = comment
209
- @stats.add_method meth
210
- end
211
-
212
- def has_modifier_nodoc?(line_no) # :nodoc:
213
- @modifier_comments[line_no]&.match?(/\A#\s*:nodoc:/)
214
- end
215
-
216
- def handle_modifier_directive(code_object, line_no) # :nodoc:
217
- if (comment_text = @modifier_comments[line_no])
218
- _text, directives = @preprocess.parse_comment(comment_text, line_no, :ruby)
219
- handle_code_object_directives(code_object, directives)
220
- end
221
- end
222
-
223
- def call_node_name_arguments(call_node) # :nodoc:
224
- return [] unless call_node.arguments
225
- call_node.arguments.arguments.map do |arg|
226
- case arg
227
- when Prism::SymbolNode
228
- arg.value
229
- when Prism::StringNode
230
- arg.unescaped
231
- end
232
- end || []
233
- end
234
-
235
- # Handles meta method comments
236
-
237
- def handle_meta_method_comment(comment, directives, node)
238
- handle_code_object_directives(@container, directives)
239
- is_call_node = node.is_a?(Prism::CallNode)
240
- singleton_method = false
241
- visibility = @visibility
242
- attributes = rw = line_no = method_name = nil
243
- directives.each do |directive, (param, line)|
244
- case directive
245
- when 'attr', 'attr_reader', 'attr_writer', 'attr_accessor'
246
- attributes = [param] if param
247
- attributes ||= call_node_name_arguments(node) if is_call_node
248
- rw = directive == 'attr_writer' ? 'W' : directive == 'attr_accessor' ? 'RW' : 'R'
249
- when 'method'
250
- method_name = param if param
251
- line_no = line
252
- when 'singleton-method'
253
- method_name = param if param
254
- line_no = line
255
- singleton_method = true
256
- visibility = :public
257
- end
258
- end
259
-
260
- if attributes
261
- attributes.each do |attr|
262
- a = RDoc::Attr.new(@container, attr, rw, comment, singleton: @singleton)
263
- a.store = @store
264
- a.line = line_no
265
- record_location(a)
266
- @container.add_attribute(a)
267
- a.visibility = visibility
268
- end
269
- elsif line_no || node
270
- method_name ||= call_node_name_arguments(node).first if is_call_node
271
- if node
272
- tokens = visible_tokens_from_location(node.location)
273
- line_no = node.location.start_line
274
- else
275
- tokens = [file_line_comment_token(line_no)]
276
- end
277
- internal_add_method(
278
- method_name,
279
- @container,
280
- comment: comment,
281
- directives: directives,
282
- dont_rename_initialize: false,
283
- line_no: line_no,
284
- visibility: visibility,
285
- singleton: @singleton || singleton_method,
286
- params: nil,
287
- calls_super: false,
288
- block_params: nil,
289
- tokens: tokens,
290
- )
291
- end
292
- end
293
-
294
- INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST = %w[
295
- method singleton-method attr attr_reader attr_writer attr_accessor
296
- ].freeze
297
- private_constant :INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST
298
-
299
- def normal_comment_treat_as_ghost_method_for_now?(directives, line_no) # :nodoc:
300
- # Meta method comment should start with `##` but some comments does not follow this rule.
301
- # For now, RDoc accepts them as a meta method comment if there is no node linked to it.
302
- !@line_nodes[line_no] && INVALID_GHOST_METHOD_ACCEPT_DIRECTIVE_LIST.any? { |directive| directives.has_key?(directive) }
303
- end
304
-
305
- def handle_standalone_consecutive_comment_directive(comment, directives, start_with_sharp_sharp, line_no, start_line) # :nodoc:
306
- if start_with_sharp_sharp && start_line != @first_non_meta_comment_start_line
307
- node = @line_nodes[line_no]
308
- handle_meta_method_comment(comment, directives, node)
309
- elsif normal_comment_treat_as_ghost_method_for_now?(directives, line_no) && start_line != @first_non_meta_comment_start_line
310
- handle_meta_method_comment(comment, directives, nil)
311
- else
312
- handle_code_object_directives(@container, directives)
313
- end
314
- end
315
-
316
- # Processes consecutive comments that were not linked to any documentable code until the given line number
317
-
318
- def process_comments_until(line_no_until)
319
- while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
320
- line_no, start_line, text = @unprocessed_comments.shift
321
- if @markup == 'tomdoc'
322
- comment = RDoc::Comment.new(text, @top_level, :ruby)
323
- comment.format = 'tomdoc'
324
- parse_comment_tomdoc(@container, comment, line_no, start_line)
325
- @preprocess.run_post_processes(comment, @container)
326
- elsif (comment_text, directives = parse_comment_text_to_directives(text, start_line))
327
- handle_standalone_consecutive_comment_directive(comment_text, directives, text.start_with?(/#\#$/), line_no, start_line)
328
- end
329
- end
330
- end
331
-
332
- # Skips all undocumentable consecutive comments until the given line number.
333
- # Undocumentable comments are comments written inside `def` or inside undocumentable class/module
334
-
335
- def skip_comments_until(line_no_until)
336
- while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
337
- @unprocessed_comments.shift
338
- end
339
- end
340
-
341
- # Returns consecutive comment linked to the given line number
342
-
343
- def consecutive_comment(line_no)
344
- return unless @unprocessed_comments.first&.first == line_no
345
- _line_no, start_line, text = @unprocessed_comments.shift
346
- parse_comment_text_to_directives(text, start_line)
347
- end
348
-
349
- # Parses comment text and retuns a pair of RDoc::Comment and directives
350
-
351
- def parse_comment_text_to_directives(comment_text, start_line) # :nodoc:
352
- comment_text, directives = @preprocess.parse_comment(comment_text, start_line, :ruby)
353
- comment = RDoc::Comment.new(comment_text, @top_level, :ruby)
354
- comment.normalized = true
355
- comment.line = start_line
356
- markup, = directives['markup']
357
- comment.format = markup&.downcase || @markup
358
- if (section, = directives['section'])
359
- # If comment has :section:, it is not a documentable comment for a code object
360
- @container.set_current_section(section, comment.dup)
361
- return
362
- end
363
- @preprocess.run_post_processes(comment, @container)
364
- [comment, directives]
365
- end
366
-
367
- def slice_tokens(start_pos, end_pos) # :nodoc:
368
- start_index = @tokens.bsearch_index { |t| ([t.line_no, t.char_no] <=> start_pos) >= 0 }
369
- end_index = @tokens.bsearch_index { |t| ([t.line_no, t.char_no] <=> end_pos) >= 0 }
370
- tokens = @tokens[start_index...end_index]
371
- tokens.pop if tokens.last&.kind == :on_nl
372
- tokens
373
- end
374
-
375
- def file_line_comment_token(line_no) # :nodoc:
376
- position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no - 1, 0, :on_comment)
377
- position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
378
- position_comment
379
- end
380
-
381
- # Returns tokens from the given location
382
-
383
- def visible_tokens_from_location(location)
384
- position_comment = file_line_comment_token(location.start_line)
385
- newline_token = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
386
- indent_token = RDoc::Parser::RipperStateLex::Token.new(location.start_line, 0, :on_sp, ' ' * location.start_character_column)
387
- tokens = slice_tokens(
388
- [location.start_line, location.start_character_column],
389
- [location.end_line, location.end_character_column]
390
- )
391
- [position_comment, newline_token, indent_token, *tokens]
392
- end
393
-
394
- # Handles `public :foo, :bar` `private :foo, :bar` and `protected :foo, :bar`
395
-
396
- def change_method_visibility(names, visibility, singleton: @singleton)
397
- new_methods = []
398
- @container.methods_matching(names, singleton) do |m|
399
- if m.parent != @container
400
- m = m.dup
401
- record_location(m)
402
- new_methods << m
403
- else
404
- m.visibility = visibility
405
- end
406
- end
407
- new_methods.each do |method|
408
- case method
409
- when RDoc::AnyMethod then
410
- @container.add_method(method)
411
- when RDoc::Attr then
412
- @container.add_attribute(method)
413
- end
414
- method.visibility = visibility
415
- end
416
- end
417
-
418
- # Handles `module_function :foo, :bar`
419
-
420
- def change_method_to_module_function(names)
421
- @container.set_visibility_for(names, :private, false)
422
- new_methods = []
423
- @container.methods_matching(names) do |m|
424
- s_m = m.dup
425
- record_location(s_m)
426
- s_m.singleton = true
427
- new_methods << s_m
428
- end
429
- new_methods.each do |method|
430
- case method
431
- when RDoc::AnyMethod then
432
- @container.add_method(method)
433
- when RDoc::Attr then
434
- @container.add_attribute(method)
435
- end
436
- method.visibility = :public
437
- end
438
- end
439
-
440
- def handle_code_object_directives(code_object, directives) # :nodoc:
441
- directives.each do |directive, (param)|
442
- @preprocess.handle_directive('', directive, param, code_object)
443
- end
444
- end
445
-
446
- # Handles `alias foo bar` and `alias_method :foo, :bar`
447
-
448
- def add_alias_method(old_name, new_name, line_no)
449
- comment, directives = consecutive_comment(line_no)
450
- handle_code_object_directives(@container, directives) if directives
451
- visibility = @container.find_method(old_name, @singleton)&.visibility || :public
452
- a = RDoc::Alias.new(nil, old_name, new_name, comment, singleton: @singleton)
453
- handle_modifier_directive(a, line_no)
454
- a.store = @store
455
- a.line = line_no
456
- record_location(a)
457
- if should_document?(a)
458
- @container.add_alias(a)
459
- @container.find_method(new_name, @singleton)&.visibility = visibility
460
- end
461
- end
462
-
463
- # Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`
464
-
465
- def add_attributes(names, rw, line_no)
466
- comment, directives = consecutive_comment(line_no)
467
- handle_code_object_directives(@container, directives) if directives
468
- return unless @container.document_children
469
-
470
- names.each do |symbol|
471
- a = RDoc::Attr.new(nil, symbol.to_s, rw, comment, singleton: @singleton)
472
- a.store = @store
473
- a.line = line_no
474
- record_location(a)
475
- handle_modifier_directive(a, line_no)
476
- @container.add_attribute(a) if should_document?(a)
477
- a.visibility = visibility # should set after adding to container
478
- end
479
- end
480
-
481
- # Adds includes/extends. Module name is resolved to full before adding.
482
-
483
- def add_includes_extends(names, rdoc_class, line_no) # :nodoc:
484
- comment, directives = consecutive_comment(line_no)
485
- handle_code_object_directives(@container, directives) if directives
486
- names.each do |name|
487
- resolved_name = resolve_constant_path(name)
488
- ie = @container.add(rdoc_class, resolved_name || name, '')
489
- ie.store = @store
490
- ie.line = line_no
491
- ie.comment = comment
492
- record_location(ie)
493
- end
494
- end
495
-
496
- # Handle `include Foo, Bar`
497
-
498
- def add_includes(names, line_no) # :nodoc:
499
- add_includes_extends(names, RDoc::Include, line_no)
500
- end
501
-
502
- # Handle `extend Foo, Bar`
503
-
504
- def add_extends(names, line_no) # :nodoc:
505
- add_includes_extends(names, RDoc::Extend, line_no)
506
- end
507
-
508
- # Adds a method defined by `def` syntax
509
-
510
- def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, start_line:, args_end_line:, end_line:)
511
- receiver = receiver_name ? find_or_create_module_path(receiver_name, receiver_fallback_type) : @container
512
- comment, directives = consecutive_comment(start_line)
513
- handle_code_object_directives(@container, directives) if directives
514
-
515
- internal_add_method(
516
- method_name,
517
- receiver,
518
- comment: comment,
519
- directives: directives,
520
- modifier_comment_lines: [start_line, args_end_line, end_line].uniq,
521
- line_no: start_line,
522
- visibility: visibility,
523
- singleton: singleton,
524
- params: params,
525
- calls_super: calls_super,
526
- block_params: block_params,
527
- tokens: tokens
528
- )
529
- end
530
-
531
- private def internal_add_method(method_name, container, comment:, dont_rename_initialize: false, directives:, modifier_comment_lines: nil, line_no:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:) # :nodoc:
532
- meth = RDoc::AnyMethod.new(nil, method_name, singleton: singleton)
533
- meth.comment = comment
534
- handle_code_object_directives(meth, directives) if directives
535
- modifier_comment_lines&.each do |line|
536
- handle_modifier_directive(meth, line)
537
- end
538
- return unless should_document?(meth)
539
-
540
- if directives && (call_seq, = directives['call-seq'])
541
- meth.call_seq = call_seq.lines.map(&:chomp).reject(&:empty?).join("\n") if call_seq
542
- end
543
- meth.name ||= meth.call_seq[/\A[^()\s]+/] if meth.call_seq
544
- meth.name ||= 'unknown'
545
- meth.store = @store
546
- meth.line = line_no
547
- container.add_method(meth) # should add after setting singleton and before setting visibility
548
- meth.visibility = visibility
549
- meth.params ||= params || '()'
550
- meth.calls_super = calls_super
551
- meth.block_params ||= block_params if block_params
552
- record_location(meth)
553
- meth.start_collecting_tokens(:ruby)
554
- tokens.each do |token|
555
- meth.token_stream << token
556
- end
557
-
558
- # Rename after add_method to register duplicated 'new' and 'initialize'
559
- # defined in c and ruby just like the old parser did.
560
- if !dont_rename_initialize && method_name == 'initialize' && !singleton
561
- if meth.dont_rename_initialize
562
- meth.visibility = :protected
563
- else
564
- meth.name = 'new'
565
- meth.singleton = true
566
- meth.visibility = :public
567
- end
568
- end
569
- end
570
-
571
- # Find or create module or class from a given module name.
572
- # If module or class does not exist, creates a module or a class according to `create_mode` argument.
573
-
574
- def find_or_create_module_path(module_name, create_mode)
575
- root_name, *path, name = module_name.split('::')
576
- add_module = ->(mod, name, mode) {
577
- case mode
578
- when :class
579
- mod.add_class(RDoc::NormalClass, name, 'Object').tap { |m| m.store = @store }
580
- when :module
581
- mod.add_module(RDoc::NormalModule, name).tap { |m| m.store = @store }
582
- end
583
- }
584
- if root_name.empty?
585
- mod = @top_level
586
- else
587
- @module_nesting.reverse_each do |nesting, singleton|
588
- next if singleton
589
- mod = nesting.get_module_named(root_name)
590
- break if mod
591
- # If a constant is found and it is not a module or class, RDoc can't document about it.
592
- # Return an anonymous module to avoid wrong document creation.
593
- return RDoc::NormalModule.new(nil) if nesting.find_constant_named(root_name)
594
- end
595
- last_nesting, = @module_nesting.reverse_each.find { |_, singleton| !singleton }
596
- return mod || add_module.call(last_nesting, root_name, create_mode) unless name
597
- mod ||= add_module.call(last_nesting, root_name, :module)
598
- end
599
- path.each do |name|
600
- mod = mod.get_module_named(name) || add_module.call(mod, name, :module)
601
- end
602
- mod.get_module_named(name) || add_module.call(mod, name, create_mode)
603
- end
604
-
605
- # Resolves constant path to a full path by searching module nesting
606
-
607
- def resolve_constant_path(constant_path)
608
- owner_name, path = constant_path.split('::', 2)
609
- return constant_path if owner_name.empty? # ::Foo, ::Foo::Bar
610
- mod = nil
611
- @module_nesting.reverse_each do |nesting, singleton|
612
- next if singleton
613
- mod = nesting.get_module_named(owner_name)
614
- break if mod
615
- end
616
- mod ||= @top_level.get_module_named(owner_name)
617
- [mod.full_name, path].compact.join('::') if mod
618
- end
619
-
620
- # Returns a pair of owner module and constant name from a given constant path.
621
- # Creates owner module if it does not exist.
622
-
623
- def find_or_create_constant_owner_name(constant_path)
624
- const_path, colon, name = constant_path.rpartition('::')
625
- if colon.empty? # class Foo
626
- # Within `class C` or `module C`, owner is C(== current container)
627
- # Within `class <<C`, owner is C.singleton_class
628
- # but RDoc don't track constants of a singleton class of module
629
- [(@singleton ? nil : @container), name]
630
- elsif const_path.empty? # class ::Foo
631
- [@top_level, name]
632
- else # `class Foo::Bar` or `class ::Foo::Bar`
633
- [find_or_create_module_path(const_path, :module), name]
634
- end
635
- end
636
-
637
- # Adds a constant
638
-
639
- def add_constant(constant_name, rhs_name, start_line, end_line)
640
- comment, directives = consecutive_comment(start_line)
641
- handle_code_object_directives(@container, directives) if directives
642
- owner, name = find_or_create_constant_owner_name(constant_name)
643
- return unless owner
644
-
645
- constant = RDoc::Constant.new(name, rhs_name, comment)
646
- constant.store = @store
647
- constant.line = start_line
648
- record_location(constant)
649
- handle_modifier_directive(constant, start_line)
650
- handle_modifier_directive(constant, end_line)
651
- owner.add_constant(constant)
652
- mod =
653
- if rhs_name =~ /^::/
654
- @store.find_class_or_module(rhs_name)
655
- else
656
- full_name = resolve_constant_path(rhs_name)
657
- @store.find_class_or_module(full_name)
658
- end
659
- if mod && constant.document_self
660
- a = @container.add_module_alias(mod, rhs_name, constant, @top_level)
661
- a.store = @store
662
- a.line = start_line
663
- record_location(a)
664
- end
665
- end
666
-
667
- # Adds module or class
668
-
669
- def add_module_or_class(module_name, start_line, end_line, is_class: false, superclass_name: nil, superclass_expr: nil)
670
- comment, directives = consecutive_comment(start_line)
671
- handle_code_object_directives(@container, directives) if directives
672
- return unless @container.document_children
673
-
674
- owner, name = find_or_create_constant_owner_name(module_name)
675
- return unless owner
676
-
677
- if is_class
678
- # RDoc::NormalClass resolves superclass name despite of the lack of module nesting information.
679
- # We need to fix it when RDoc::NormalClass resolved to a wrong constant name
680
- if superclass_name
681
- superclass_full_path = resolve_constant_path(superclass_name)
682
- superclass = @store.find_class_or_module(superclass_full_path) if superclass_full_path
683
- superclass_full_path ||= superclass_name
684
- superclass_full_path = superclass_full_path.sub(/^::/, '')
685
- end
686
- # add_class should be done after resolving superclass
687
- mod = owner.classes_hash[name] || owner.add_class(RDoc::NormalClass, name, superclass_name || superclass_expr || '::Object')
688
- if superclass_name
689
- if superclass
690
- mod.superclass = superclass
691
- elsif (mod.superclass.is_a?(String) || mod.superclass.name == 'Object') && mod.superclass != superclass_full_path
692
- mod.superclass = superclass_full_path
693
- end
694
- end
695
- else
696
- mod = owner.modules_hash[name] || owner.add_module(RDoc::NormalModule, name)
697
- end
698
-
699
- mod.store = @store
700
- mod.line = start_line
701
- record_location(mod)
702
- handle_modifier_directive(mod, start_line)
703
- handle_modifier_directive(mod, end_line)
704
- mod.add_comment(comment, @top_level) if comment
705
- mod
706
- end
707
-
708
- class RDocVisitor < Prism::Visitor # :nodoc:
709
- def initialize(scanner, top_level, store)
710
- @scanner = scanner
711
- @top_level = top_level
712
- @store = store
713
- end
714
-
715
- def visit_if_node(node)
716
- if node.end_keyword
717
- super
718
- else
719
- # Visit with the order in text representation to handle this method comment
720
- # # comment
721
- # def f
722
- # end if call_node
723
- node.statements.accept(self)
724
- node.predicate.accept(self)
725
- end
726
- end
727
- alias visit_unless_node visit_if_node
728
-
729
- def visit_call_node(node)
730
- @scanner.process_comments_until(node.location.start_line - 1)
731
- if node.receiver.nil?
732
- case node.name
733
- when :attr
734
- _visit_call_attr_reader_writer_accessor(node, 'R')
735
- when :attr_reader
736
- _visit_call_attr_reader_writer_accessor(node, 'R')
737
- when :attr_writer
738
- _visit_call_attr_reader_writer_accessor(node, 'W')
739
- when :attr_accessor
740
- _visit_call_attr_reader_writer_accessor(node, 'RW')
741
- when :include
742
- _visit_call_include(node)
743
- when :extend
744
- _visit_call_extend(node)
745
- when :public
746
- super
747
- _visit_call_public_private_protected(node, :public)
748
- when :private
749
- super
750
- _visit_call_public_private_protected(node, :private)
751
- when :protected
752
- super
753
- _visit_call_public_private_protected(node, :protected)
754
- when :private_constant
755
- _visit_call_private_constant(node)
756
- when :public_constant
757
- _visit_call_public_constant(node)
758
- when :require
759
- _visit_call_require(node)
760
- when :alias_method
761
- _visit_call_alias_method(node)
762
- when :module_function
763
- super
764
- _visit_call_module_function(node)
765
- when :public_class_method
766
- super
767
- _visit_call_public_private_class_method(node, :public)
768
- when :private_class_method
769
- super
770
- _visit_call_public_private_class_method(node, :private)
771
- else
772
- super
773
- end
774
- else
775
- super
776
- end
777
- end
778
-
779
- def visit_block_node(node)
780
- @scanner.with_in_proc_block do
781
- # include, extend and method definition inside block are not documentable.
782
- # visibility methods and attribute definition methods should be ignored inside block.
783
- super
784
- end
785
- end
786
-
787
- def visit_alias_method_node(node)
788
- return if @scanner.in_proc_block
789
- @scanner.process_comments_until(node.location.start_line - 1)
790
- return unless node.old_name.is_a?(Prism::SymbolNode) && node.new_name.is_a?(Prism::SymbolNode)
791
- @scanner.add_alias_method(node.old_name.value.to_s, node.new_name.value.to_s, node.location.start_line)
792
- end
793
-
794
- def visit_module_node(node)
795
- node.constant_path.accept(self)
796
- @scanner.process_comments_until(node.location.start_line - 1)
797
- module_name = constant_path_string(node.constant_path)
798
- mod = @scanner.add_module_or_class(module_name, node.location.start_line, node.location.end_line) if module_name
799
- if mod
800
- @scanner.with_container(mod) do
801
- node.body&.accept(self)
802
- @scanner.process_comments_until(node.location.end_line)
803
- end
804
- else
805
- @scanner.skip_comments_until(node.location.end_line)
806
- end
807
- end
808
-
809
- def visit_class_node(node)
810
- node.constant_path.accept(self)
811
- node.superclass&.accept(self)
812
- @scanner.process_comments_until(node.location.start_line - 1)
813
- superclass_name = constant_path_string(node.superclass) if node.superclass
814
- superclass_expr = node.superclass.slice if node.superclass && !superclass_name
815
- class_name = constant_path_string(node.constant_path)
816
- klass = @scanner.add_module_or_class(class_name, node.location.start_line, node.location.end_line, is_class: true, superclass_name: superclass_name, superclass_expr: superclass_expr) if class_name
817
- if klass
818
- @scanner.with_container(klass) do
819
- node.body&.accept(self)
820
- @scanner.process_comments_until(node.location.end_line)
821
- end
822
- else
823
- @scanner.skip_comments_until(node.location.end_line)
824
- end
825
- end
826
-
827
- def visit_singleton_class_node(node)
828
- @scanner.process_comments_until(node.location.start_line - 1)
829
-
830
- if @scanner.has_modifier_nodoc?(node.location.start_line)
831
- # Skip visiting inside the singleton class. Also skips creation of node.expression as a module
832
- @scanner.skip_comments_until(node.location.end_line)
833
- return
834
- end
835
-
836
- expression = node.expression
837
- expression = expression.body.body.first if expression.is_a?(Prism::ParenthesesNode) && expression.body&.body&.size == 1
838
-
839
- case expression
840
- when Prism::ConstantWriteNode
841
- # Accept `class << (NameErrorCheckers = Object.new)` as a module which is not actually a module
842
- mod = @scanner.container.add_module(RDoc::NormalModule, expression.name.to_s)
843
- when Prism::ConstantPathNode, Prism::ConstantReadNode
844
- expression_name = constant_path_string(expression)
845
- # If a constant_path does not exist, RDoc creates a module
846
- mod = @scanner.find_or_create_module_path(expression_name, :module) if expression_name
847
- when Prism::SelfNode
848
- mod = @scanner.container if @scanner.container != @top_level
849
- end
850
- expression.accept(self)
851
- if mod
852
- @scanner.with_container(mod, singleton: true) do
853
- node.body&.accept(self)
854
- @scanner.process_comments_until(node.location.end_line)
855
- end
856
- else
857
- @scanner.skip_comments_until(node.location.end_line)
858
- end
859
- end
860
-
861
- def visit_def_node(node)
862
- start_line = node.location.start_line
863
- args_end_line = node.parameters&.location&.end_line || start_line
864
- end_line = node.location.end_line
865
- @scanner.process_comments_until(start_line - 1)
866
-
867
- return if @scanner.in_proc_block
868
-
869
- case node.receiver
870
- when Prism::NilNode, Prism::TrueNode, Prism::FalseNode
871
- visibility = :public
872
- singleton = false
873
- receiver_name =
874
- case node.receiver
875
- when Prism::NilNode
876
- 'NilClass'
877
- when Prism::TrueNode
878
- 'TrueClass'
879
- when Prism::FalseNode
880
- 'FalseClass'
881
- end
882
- receiver_fallback_type = :class
883
- when Prism::SelfNode
884
- # singleton method of a singleton class is not documentable
885
- return if @scanner.singleton
886
- visibility = :public
887
- singleton = true
888
- when Prism::ConstantReadNode, Prism::ConstantPathNode
889
- visibility = :public
890
- singleton = true
891
- receiver_name = constant_path_string(node.receiver)
892
- receiver_fallback_type = :module
893
- return unless receiver_name
894
- when nil
895
- visibility = @scanner.visibility
896
- singleton = @scanner.singleton
897
- else
898
- # `def (unknown expression).method_name` is not documentable
899
- return
900
- end
901
- name = node.name.to_s
902
- params, block_params, calls_super = MethodSignatureVisitor.scan_signature(node)
903
- tokens = @scanner.visible_tokens_from_location(node.location)
904
-
905
- @scanner.add_method(
906
- name,
907
- receiver_name: receiver_name,
908
- receiver_fallback_type: receiver_fallback_type,
909
- visibility: visibility,
910
- singleton: singleton,
911
- params: params,
912
- block_params: block_params,
913
- calls_super: calls_super,
914
- tokens: tokens,
915
- start_line: start_line,
916
- args_end_line: args_end_line,
917
- end_line: end_line
918
- )
919
- ensure
920
- @scanner.skip_comments_until(end_line)
921
- end
922
-
923
- def visit_constant_path_write_node(node)
924
- @scanner.process_comments_until(node.location.start_line - 1)
925
- path = constant_path_string(node.target)
926
- return unless path
927
-
928
- @scanner.add_constant(
929
- path,
930
- constant_path_string(node.value) || node.value.slice,
931
- node.location.start_line,
932
- node.location.end_line
933
- )
934
- @scanner.skip_comments_until(node.location.end_line)
935
- # Do not traverse rhs not to document `A::B = Struct.new{def undocumentable_method; end}`
936
- end
937
-
938
- def visit_constant_write_node(node)
939
- @scanner.process_comments_until(node.location.start_line - 1)
940
- @scanner.add_constant(
941
- node.name.to_s,
942
- constant_path_string(node.value) || node.value.slice,
943
- node.location.start_line,
944
- node.location.end_line
945
- )
946
- @scanner.skip_comments_until(node.location.end_line)
947
- # Do not traverse rhs not to document `A = Struct.new{def undocumentable_method; end}`
948
- end
949
-
950
- private
951
-
952
- def constant_arguments_names(call_node)
953
- return unless call_node.arguments
954
- names = call_node.arguments.arguments.map { |arg| constant_path_string(arg) }
955
- names.all? ? names : nil
956
- end
957
-
958
- def symbol_arguments(call_node)
959
- arguments_node = call_node.arguments
960
- return unless arguments_node && arguments_node.arguments.all? { |arg| arg.is_a?(Prism::SymbolNode)}
961
- arguments_node.arguments.map { |arg| arg.value.to_sym }
962
- end
963
-
964
- def visibility_method_arguments(call_node, singleton:)
965
- arguments_node = call_node.arguments
966
- return unless arguments_node
967
- symbols = symbol_arguments(call_node)
968
- if symbols
969
- # module_function :foo, :bar
970
- return symbols.map(&:to_s)
971
- else
972
- return unless arguments_node.arguments.size == 1
973
- arg = arguments_node.arguments.first
974
- return unless arg.is_a?(Prism::DefNode)
975
-
976
- if singleton
977
- # `private_class_method def foo; end` `private_class_method def not_self.foo; end` should be ignored
978
- return unless arg.receiver.is_a?(Prism::SelfNode)
979
- else
980
- # `module_function def something.foo` should be ignored
981
- return if arg.receiver
982
- end
983
- # `module_function def foo; end` or `private_class_method def self.foo; end`
984
- [arg.name.to_s]
985
- end
986
- end
987
-
988
- def constant_path_string(node)
989
- case node
990
- when Prism::ConstantReadNode
991
- node.name.to_s
992
- when Prism::ConstantPathNode
993
- parent_name = node.parent ? constant_path_string(node.parent) : ''
994
- "#{parent_name}::#{node.name}" if parent_name
995
- end
996
- end
997
-
998
- def _visit_call_require(call_node)
999
- return unless call_node.arguments&.arguments&.size == 1
1000
- arg = call_node.arguments.arguments.first
1001
- return unless arg.is_a?(Prism::StringNode)
1002
- @scanner.container.add_require(RDoc::Require.new(arg.unescaped, nil))
1003
- end
1004
-
1005
- def _visit_call_module_function(call_node)
1006
- return if @scanner.in_proc_block || @scanner.singleton
1007
- names = visibility_method_arguments(call_node, singleton: false)&.map(&:to_s)
1008
- @scanner.change_method_to_module_function(names) if names
1009
- end
1010
-
1011
- def _visit_call_public_private_class_method(call_node, visibility)
1012
- return if @scanner.in_proc_block || @scanner.singleton
1013
- names = visibility_method_arguments(call_node, singleton: true)
1014
- @scanner.change_method_visibility(names, visibility, singleton: true) if names
1015
- end
1016
-
1017
- def _visit_call_public_private_protected(call_node, visibility)
1018
- return if @scanner.in_proc_block
1019
- arguments_node = call_node.arguments
1020
- if arguments_node.nil? # `public` `private`
1021
- @scanner.visibility = visibility
1022
- else # `public :foo, :bar`, `private def foo; end`
1023
- names = visibility_method_arguments(call_node, singleton: false)
1024
- @scanner.change_method_visibility(names, visibility) if names
1025
- end
1026
- end
1027
-
1028
- def _visit_call_alias_method(call_node)
1029
- return if @scanner.in_proc_block
1030
-
1031
- new_name, old_name, *rest = symbol_arguments(call_node)
1032
- return unless old_name && new_name && rest.empty?
1033
- @scanner.add_alias_method(old_name.to_s, new_name.to_s, call_node.location.start_line)
1034
- end
1035
-
1036
- def _visit_call_include(call_node)
1037
- return if @scanner.in_proc_block
1038
-
1039
- names = constant_arguments_names(call_node)
1040
- line_no = call_node.location.start_line
1041
- return unless names
1042
-
1043
- if @scanner.singleton
1044
- @scanner.add_extends(names, line_no)
1045
- else
1046
- @scanner.add_includes(names, line_no)
1047
- end
1048
- end
1049
-
1050
- def _visit_call_extend(call_node)
1051
- return if @scanner.in_proc_block
1052
-
1053
- names = constant_arguments_names(call_node)
1054
- @scanner.add_extends(names, call_node.location.start_line) if names && !@scanner.singleton
1055
- end
1056
-
1057
- def _visit_call_public_constant(call_node)
1058
- return if @scanner.in_proc_block || @scanner.singleton
1059
- names = symbol_arguments(call_node)
1060
- @scanner.container.set_constant_visibility_for(names.map(&:to_s), :public) if names
1061
- end
1062
-
1063
- def _visit_call_private_constant(call_node)
1064
- return if @scanner.in_proc_block || @scanner.singleton
1065
- names = symbol_arguments(call_node)
1066
- @scanner.container.set_constant_visibility_for(names.map(&:to_s), :private) if names
1067
- end
1068
-
1069
- def _visit_call_attr_reader_writer_accessor(call_node, rw)
1070
- return if @scanner.in_proc_block
1071
- names = symbol_arguments(call_node)
1072
- @scanner.add_attributes(names.map(&:to_s), rw, call_node.location.start_line) if names
1073
- end
1074
-
1075
- class MethodSignatureVisitor < Prism::Visitor # :nodoc:
1076
- class << self
1077
- def scan_signature(def_node)
1078
- visitor = new
1079
- def_node.body&.accept(visitor)
1080
- params = "(#{def_node.parameters&.slice})"
1081
- block_params = visitor.yields.first
1082
- [params, block_params, visitor.calls_super]
1083
- end
1084
- end
1085
-
1086
- attr_reader :params, :yields, :calls_super
1087
-
1088
- def initialize
1089
- @params = nil
1090
- @calls_super = false
1091
- @yields = []
1092
- end
1093
-
1094
- def visit_def_node(node)
1095
- # stop traverse inside nested def
1096
- end
1097
-
1098
- def visit_yield_node(node)
1099
- @yields << (node.arguments&.slice || '')
1100
- end
1101
-
1102
- def visit_super_node(node)
1103
- @calls_super = true
1104
- super
1105
- end
1106
-
1107
- def visit_forwarding_super_node(node)
1108
- @calls_super = true
1109
- end
1110
- end
1111
- end
1112
- end