22
33require 'prism'
44require_relative 'ripper_state_lex'
5+ require_relative '../rbs_helper'
56
67# Unlike lib/rdoc/parser/ripper_ruby.rb, this file is not based on rtags and does not contain code from
78# rtags.rb -
@@ -133,6 +134,9 @@ class RDoc::Parser::PrismRuby < RDoc::Parser
133134
134135 parse_files_matching ( /\. rbw?$/ ) unless ENV [ 'RDOC_USE_RIPPER_PARSER' ]
135136
137+ # Matches an RBS inline type annotation line: #: followed by whitespace
138+ RBS_SIG_LINE = /\A #:\s / # :nodoc:
139+
136140 attr_accessor :visibility
137141 attr_reader :container , :singleton , :in_proc_block
138142
@@ -461,10 +465,14 @@ def skip_comments_until(line_no_until)
461465 def consecutive_comment ( line_no )
462466 return unless @unprocessed_comments . first &.first == line_no
463467 _line_no , start_line , text = @unprocessed_comments . shift
464- parse_comment_text_to_directives ( text , start_line )
468+ type_signature = extract_type_signature! ( text , start_line )
469+ result = parse_comment_text_to_directives ( text , start_line )
470+ return unless result
471+ comment , directives = result
472+ [ comment , directives , type_signature ]
465473 end
466474
467- # Parses comment text and retuns a pair of RDoc::Comment and directives
475+ # Parses comment text and returns a pair of RDoc::Comment and directives
468476
469477 def parse_comment_text_to_directives ( comment_text , start_line ) # :nodoc:
470478 comment_text , directives = @preprocess . parse_comment ( comment_text , start_line , :ruby )
@@ -594,14 +602,15 @@ def add_alias_method(old_name, new_name, line_no)
594602 # Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`
595603
596604 def add_attributes ( names , rw , line_no )
597- comment , directives = consecutive_comment ( line_no )
605+ comment , directives , type_signature = consecutive_comment ( line_no )
598606 handle_code_object_directives ( @container , directives ) if directives
599607 return unless @container . document_children
600608
601609 names . each do |symbol |
602610 a = RDoc ::Attr . new ( nil , symbol . to_s , rw , comment , singleton : @singleton )
603611 a . store = @store
604612 a . line = line_no
613+ a . type_signature = type_signature
605614 record_location ( a )
606615 handle_modifier_directive ( a , line_no )
607616 @container . add_attribute ( a ) if should_document? ( a )
@@ -640,7 +649,7 @@ def add_extends(names, line_no) # :nodoc:
640649
641650 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 :)
642651 receiver = receiver_name ? find_or_create_module_path ( receiver_name , receiver_fallback_type ) : @container
643- comment , directives = consecutive_comment ( start_line )
652+ comment , directives , type_signature = consecutive_comment ( start_line )
644653 handle_code_object_directives ( @container , directives ) if directives
645654
646655 internal_add_method (
@@ -655,11 +664,12 @@ def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:
655664 params : params ,
656665 calls_super : calls_super ,
657666 block_params : block_params ,
658- tokens : tokens
667+ tokens : tokens ,
668+ type_signature : type_signature
659669 )
660670 end
661671
662- 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:
672+ 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 :, type_signature : nil ) # :nodoc:
663673 meth = RDoc ::AnyMethod . new ( nil , method_name , singleton : singleton )
664674 meth . comment = comment
665675 handle_code_object_directives ( meth , directives ) if directives
@@ -680,6 +690,7 @@ def add_method(method_name, receiver_name:, receiver_fallback_type:, visibility:
680690 meth . params ||= params || '()'
681691 meth . calls_super = calls_super
682692 meth . block_params ||= block_params if block_params
693+ meth . type_signature = type_signature
683694 record_location ( meth )
684695 meth . start_collecting_tokens ( :ruby )
685696 tokens . each do |token |
@@ -836,6 +847,36 @@ def add_module_or_class(module_name, start_line, end_line, is_class: false, supe
836847 mod
837848 end
838849
850+ private
851+
852+ # Extracts RBS type signature lines (#: ...) from raw comment text.
853+ # Mutates the input text to remove the extracted lines.
854+ # Returns the type signature string, or nil if none found.
855+
856+ def extract_type_signature! ( text , start_line )
857+ return nil unless text . include? ( '#:' )
858+
859+ lines = text . lines
860+ sig_lines , doc_lines = lines . partition { |l | l . match? ( RBS_SIG_LINE ) }
861+ return nil if sig_lines . empty?
862+
863+ first_sig_line = start_line + lines . index ( sig_lines . first )
864+ text . replace ( doc_lines . join )
865+ type_sig = sig_lines . map { |l | l . sub ( RBS_SIG_LINE , '' ) } . join . chomp
866+ return nil if type_sig . strip . empty?
867+
868+ warn_invalid_type_signature ( type_sig , first_sig_line )
869+ type_sig
870+ end
871+
872+ def warn_invalid_type_signature ( sig , line_no )
873+ sig . each_line ( chomp : true ) . with_index do |line , i |
874+ next if RDoc ::RbsHelper . valid_method_type? ( line )
875+ next if RDoc ::RbsHelper . valid_type? ( line )
876+ @options . warn "#{ @top_level . relative_name } :#{ line_no + i } : invalid RBS type signature: #{ line . inspect } "
877+ end
878+ end
879+
839880 class RDocVisitor < Prism ::Visitor # :nodoc:
840881 def initialize ( scanner , top_level , store )
841882 @scanner = scanner
0 commit comments