Skip to content

Commit 042d39c

Browse files
committed
WIP
1 parent a549d20 commit 042d39c

3 files changed

Lines changed: 100 additions & 9 deletions

File tree

lib/rbs/ast/ruby/members.rb

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,30 @@ def initialize(buffer)
1717
class MethodTypeAnnotation
1818
class DocStyle
1919
attr_accessor :return_type_annotation
20+
attr_reader :param_type_annotations
2021

2122
def initialize
2223
@return_type_annotation = nil
24+
@param_type_annotations = []
2325
end
2426

2527
def map_type_name(&block)
2628
DocStyle.new.tap do |new|
2729
new.return_type_annotation = return_type_annotation&.map_type_name(&block)
30+
new.param_type_annotations.replace(
31+
param_type_annotations.map {|annot| annot.map_type_name(&block) }
32+
)
2833
end #: self
2934
end
3035

3136
def type_fingerprint
32-
return_type_annotation&.type_fingerprint
37+
[
38+
return_type_annotation&.type_fingerprint,
39+
param_type_annotations.map(&:type_fingerprint)
40+
]
3341
end
3442

35-
def method_type
43+
def method_type(node)
3644
return_type =
3745
case return_type_annotation
3846
when Annotations::NodeTypeAssertion
@@ -43,12 +51,47 @@ def method_type
4351
Types::Bases::Any.new(location: nil)
4452
end
4553

54+
required_positionals = [] #: Array[Types::Function::Param]
55+
required_keywords = {} #: Hash[Symbol, Types::Function::Param]
56+
57+
if node.parameters
58+
params = node.parameters #: Prism::ParametersNode
59+
60+
params.requireds.each do |param|
61+
if param.is_a?(Prism::RequiredParameterNode)
62+
annotation = param_type_annotations.find { _1.name_location.source.to_sym == param.name }
63+
param_type = annotation&.param_type || Types::Bases::Any.new(location: nil)
64+
required_positionals << Types::Function::Param.new(type: param_type, name: nil)
65+
end
66+
end
67+
68+
params.optionals.each do |param|
69+
if param.is_a?(Prism::OptionalParameterNode)
70+
annotation = param_type_annotations.find { _1.name_location.source.to_sym == param.name }
71+
param_type = annotation&.param_type || Types::Bases::Any.new(location: nil)
72+
required_keywords[param.name] = Types::Function::Param.new(type: param_type, name: nil)
73+
end
74+
end
75+
76+
params.keywords.each do |param|
77+
if param.is_a?(Prism::RequiredKeywordParameterNode)
78+
annotation = param_type_annotations.find { _1.name_location.source.to_sym == param.name }
79+
param_type = annotation&.param_type || Types::Bases::Any.new(location: nil)
80+
required_keywords[param.name] = Types::Function::Param.new(type: param_type, name: nil)
81+
elsif param.is_a?(Prism::OptionalKeywordParameterNode)
82+
annotation = param_type_annotations.find { _1.name_location.source.to_sym == param.name }
83+
param_type = annotation&.param_type || Types::Bases::Any.new(location: nil)
84+
required_keywords[param.name] = Types::Function::Param.new(type: param_type, name: nil)
85+
end
86+
end
87+
end
88+
4689
type = Types::Function.new(
47-
required_positionals: [],
90+
required_positionals: required_positionals,
4891
optional_positionals: [],
4992
rest_positionals: nil,
5093
trailing_positionals: [],
51-
required_keywords: {},
94+
required_keywords: required_keywords,
5295
optional_keywords: {},
5396
rest_keywords: nil,
5497
return_type: return_type
@@ -125,6 +168,15 @@ def self.build(leading_block, trailing_block, variables)
125168
next
126169
end
127170
end
171+
when Annotations::ParamTypeAnnotation
172+
unless type_annotations
173+
type_annotations = DocStyle.new()
174+
end
175+
176+
if type_annotations.is_a?(DocStyle)
177+
type_annotations.param_type_annotations << paragraph
178+
next
179+
end
128180
end
129181

130182
unused_annotations << paragraph
@@ -144,10 +196,10 @@ def empty?
144196
type_annotations.nil?
145197
end
146198

147-
def overloads
199+
def overloads(node)
148200
case type_annotations
149201
when DocStyle
150-
method_type = type_annotations.method_type
202+
method_type = type_annotations.method_type(node)
151203

152204
[
153205
AST::Members::MethodDefinition::Overload.new(annotations: [], method_type: method_type)
@@ -224,7 +276,7 @@ def location
224276
end
225277

226278
def overloads
227-
method_type.overloads
279+
method_type.overloads(node)
228280
end
229281

230282
def overloading?

sig/ast/ruby/members.rbs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ module RBS
1919

2020
class MethodTypeAnnotation
2121
class DocStyle
22+
type param_type_annotation = Annotations::ParamTypeAnnotation
23+
2224
attr_accessor return_type_annotation: Annotations::ReturnTypeAnnotation | Annotations::NodeTypeAssertion | nil
2325

26+
attr_reader param_type_annotations: Array[param_type_annotation]
27+
2428
def initialize: () -> void
2529

2630
def map_type_name: () { (TypeName) -> TypeName } -> self
2731

28-
def method_type: () -> MethodType
32+
def method_type: (Prism::DefNode) -> MethodType
2933

3034
def type_fingerprint: () -> untyped
3135
end
@@ -53,7 +57,7 @@ module RBS
5357

5458
# Returns the method type overloads
5559
#
56-
def overloads: () -> Array[AST::Members::MethodDefinition::Overload]
60+
def overloads: (Prism::DefNode) -> Array[AST::Members::MethodDefinition::Overload]
5761

5862
def overloading?: () -> bool
5963

test/rbs/inline_parser_test.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,41 @@ def add(x, y)
275275
end
276276
end
277277

278+
def test_parse__def_method_docs
279+
result = parse(<<~RUBY)
280+
class Foo
281+
# @rbs x: Integer
282+
# @rbs y: Integer
283+
# @rbs a: String
284+
# @rbs b: String?
285+
# @rbs return: String
286+
def add(x, y = 3, a:, b: nil)
287+
end
288+
end
289+
RUBY
290+
291+
assert_empty result.diagnostics
292+
293+
result.declarations[0].tap do |decl|
294+
decl.members[0].tap do |member|
295+
assert_instance_of RBS::AST::Ruby::Members::DefMember, member
296+
assert_equal ["(Integer, y: Integer, a: String, b: String?) -> String"], member.overloads.map { _1.method_type.to_s }
297+
end
298+
end
299+
end
300+
301+
302+
def test_error__def_method_docs
303+
result = parse(<<~RUBY)
304+
class Foo
305+
# @rbs x: Integer
306+
# @rbs return: void
307+
def add(y)
308+
end
309+
end
310+
RUBY
311+
end
312+
278313
def test_parse__skip_class_module
279314
result = parse(<<~RUBY)
280315
# @rbs skip -- not a constant

0 commit comments

Comments
 (0)