diff --git a/lib/rbs/ast/ruby/comment_block.rb b/lib/rbs/ast/ruby/comment_block.rb index 72a07ea5d2..fa05612d8d 100644 --- a/lib/rbs/ast/ruby/comment_block.rb +++ b/lib/rbs/ast/ruby/comment_block.rb @@ -177,6 +177,13 @@ def line_location(start_line, end_line) Location.new(comment_buffer, start_offset, end_offset) end + def location() + first_comment = comments[0] or raise + last_comment = comments[-1] or raise + + comment_buffer.rbs_location(first_comment.location.join last_comment.location) + end + def parse_annotation_lines(start_line, end_line, variables) start_pos = comment_buffer.ranges[start_line].begin end_pos = comment_buffer.ranges[end_line].end diff --git a/lib/rbs/ast/ruby/members.rb b/lib/rbs/ast/ruby/members.rb index a452eeca36..c4105d25b1 100644 --- a/lib/rbs/ast/ruby/members.rb +++ b/lib/rbs/ast/ruby/members.rb @@ -183,12 +183,14 @@ class DefMember < Base attr_reader :name attr_reader :node attr_reader :method_type + attr_reader :leading_comment - def initialize(buffer, name, node, method_type) + def initialize(buffer, name, node, method_type, leading_comment) super(buffer) @name = name @node = node @method_type = method_type + @leading_comment = leading_comment end def location diff --git a/lib/rbs/definition.rb b/lib/rbs/definition.rb index 05baf6633f..a2bbcdbfcd 100644 --- a/lib/rbs/definition.rb +++ b/lib/rbs/definition.rb @@ -66,7 +66,25 @@ def comment when AST::Members::Base member.comment when AST::Ruby::Members::Base - nil + if member.leading_comment + lines = [] #: Array[String] + + member.leading_comment.each_paragraph([]) do |paragraph| + case paragraph + when Location + lines << paragraph.local_source + end + end + + string = lines.join("\n") + + unless string.strip.empty? + AST::Comment.new( + string: string, + location: member.leading_comment.location + ) + end + end end end diff --git a/lib/rbs/environment.rb b/lib/rbs/environment.rb index deed6a8dfe..4dc3f2f894 100644 --- a/lib/rbs/environment.rb +++ b/lib/rbs/environment.rb @@ -722,7 +722,8 @@ def resolve_ruby_member(resolver, member, context:) member.buffer, member.name, member.node, - member.method_type.map_type_name {|name, _, _| absolute_type_name(resolver, nil, name, context: context) } + member.method_type.map_type_name {|name, _, _| absolute_type_name(resolver, nil, name, context: context) }, + member.leading_comment ) when AST::Ruby::Members::IncludeMember resolved_annotation = member.annotation&.map_type_name {|name, _, _| absolute_type_name(resolver, nil, name, context: context) } diff --git a/lib/rbs/inline_parser.rb b/lib/rbs/inline_parser.rb index a9ae241cd2..0f49ed1779 100644 --- a/lib/rbs/inline_parser.rb +++ b/lib/rbs/inline_parser.rb @@ -157,7 +157,7 @@ def visit_def_node(node) method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, []) report_unused_annotation(trailing_unused, *leading_unuseds) - defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type) + defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block) current.members << defn # Skip other comments in `def` node diff --git a/sig/ast/ruby/comment_block.rbs b/sig/ast/ruby/comment_block.rbs index 7dd7bde036..62cd03dda2 100644 --- a/sig/ast/ruby/comment_block.rbs +++ b/sig/ast/ruby/comment_block.rbs @@ -112,6 +112,8 @@ module RBS def line_location: (Integer start_line, Integer end_line) -> Location + def location: () -> Location + private def leading_annotation?: (Integer index) -> bool end end diff --git a/sig/ast/ruby/members.rbs b/sig/ast/ruby/members.rbs index 7299643799..843e41d8bf 100644 --- a/sig/ast/ruby/members.rbs +++ b/sig/ast/ruby/members.rbs @@ -57,8 +57,9 @@ module RBS attr_reader name: Symbol attr_reader node: Prism::DefNode attr_reader method_type: MethodTypeAnnotation + attr_reader leading_comment: CommentBlock? - def initialize: (Buffer, Symbol name, Prism::DefNode node, MethodTypeAnnotation) -> void + def initialize: (Buffer, Symbol name, Prism::DefNode node, MethodTypeAnnotation, CommentBlock? leading_comment) -> void def location: () -> Location diff --git a/test/rbs/definition_builder_test.rb b/test/rbs/definition_builder_test.rb index d8d55680c4..84a4ebac47 100644 --- a/test/rbs/definition_builder_test.rb +++ b/test/rbs/definition_builder_test.rb @@ -3373,7 +3373,6 @@ class TypedAttributeTest end end - def test_ruby_attribute_members_multiple_names SignatureManager.new do |manager| manager.add_ruby_file("multiple_attributes.rb", <<~RUBY) @@ -3405,4 +3404,81 @@ class MultipleAttributeTest end end end + + def test_ruby_attribute_members_docs + SignatureManager.new do |manager| + manager.add_ruby_file("a.rb", <<~RUBY) + class MultipleAttributeTest + # This is a document for attribute + # + # @rbs () -> String + attr_reader :test #: String + + # Line 1 + # + # Line 2 + # @rbs () -> String -- this is ignored + # + # Line 3 + attr_reader :test2 #: untyped + end + RUBY + + manager.build do |env| + builder = DefinitionBuilder.new(env: env) + + builder.build_instance(type_name("::MultipleAttributeTest")).tap do |definition| + definition.methods[:test].tap do |method| + assert_equal ["This is a document for attribute\n"], method.comments.map(&:string) + end + + definition.methods[:test2].tap do |method| + assert_equal ["Line 1\n\nLine 2\n\nLine 3"], method.comments.map(&:string) + end + end + end + end + end + + def test_ruby_def_members_docs + SignatureManager.new do |manager| + manager.add_ruby_file("a.rb", <<~RUBY) + class MultipleAttributeTest + # This is a document for foo method + # + # @rbs return: String? + def foo = nil + + # Line 1 + # + # Line 2 + # @rbs () -> Integer + # + # Line 3 + def bar = 123 + + # @rbs return: untyped + def baz = nil + end + RUBY + + manager.build do |env| + builder = DefinitionBuilder.new(env: env) + + builder.build_instance(type_name("::MultipleAttributeTest")).tap do |definition| + definition.methods[:foo].tap do |method| + assert_equal ["This is a document for foo method\n"], method.comments.map(&:string) + end + + definition.methods[:bar].tap do |method| + assert_equal ["Line 1\n\nLine 2\n\nLine 3"], method.comments.map(&:string) + end + + definition.methods[:baz].tap do |method| + assert_equal [], method.comments + end + end + end + end + end end