Skip to content

Commit c929a5d

Browse files
committed
Parse T::Enum values as special nodes
Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
1 parent 8d42aff commit c929a5d

7 files changed

Lines changed: 91 additions & 17 deletions

File tree

lib/rbi/index.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,17 @@ class TEnumBlock
217217
# @override
218218
#: -> Array[String]
219219
def index_ids
220-
[to_s]
220+
[fully_qualified_name]
221+
end
222+
end
223+
224+
class TEnumValue
225+
include Indexable
226+
227+
# @override
228+
#: -> Array[String]
229+
def index_ids
230+
[fully_qualified_name]
221231
end
222232
end
223233
end

lib/rbi/model.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,29 @@ def to_s
10371037
end
10381038
end
10391039

1040+
class TEnumValue < NodeWithComments
1041+
#: String
1042+
attr_reader :name
1043+
1044+
#: (String name, ?loc: Loc?, ?comments: Array[Comment]) ?{ (TEnumValue node) -> void } -> void
1045+
def initialize(name, loc: nil, comments: [], &block)
1046+
super(loc: loc, comments: comments)
1047+
@name = name
1048+
block&.call(self)
1049+
end
1050+
1051+
#: -> String
1052+
def fully_qualified_name
1053+
"#{parent_scope&.fully_qualified_name}::#{name}"
1054+
end
1055+
1056+
# @override
1057+
#: -> String
1058+
def to_s
1059+
fully_qualified_name
1060+
end
1061+
end
1062+
10401063
# Sorbet's misc.
10411064

10421065
class Helper < NodeWithComments

lib/rbi/parser.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,17 @@ def visit_constant_assign(node)
229229
loc: node_loc(node),
230230
comments: node_comments(node),
231231
)
232+
elsif t_enum_value?(node)
233+
TEnumValue.new(
234+
case node
235+
when Prism::ConstantWriteNode
236+
node.name.to_s
237+
when Prism::ConstantPathWriteNode
238+
node_string!(node.target)
239+
end,
240+
loc: node_loc(node),
241+
comments: node_comments(node),
242+
)
232243
else
233244
Const.new(
234245
case node
@@ -819,6 +830,11 @@ def set_root_tree_loc
819830
def type_variable_definition?(node)
820831
node.is_a?(Prism::CallNode) && (node.message == "type_member" || node.message == "type_template")
821832
end
833+
834+
#: (Prism::Node? node) -> bool
835+
def t_enum_value?(node)
836+
current_scope.is_a?(TEnumBlock) && node.is_a?(Prism::ConstantWriteNode) && node.value.slice == "new"
837+
end
822838
end
823839

824840
class SigBuilder < Visitor

lib/rbi/printer.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,16 @@ def visit_tenum_block(node)
542542
printl("end")
543543
end
544544

545+
# @override
546+
#: (TEnumValue node) -> void
547+
def visit_tenum_value(node)
548+
print_blank_line_before(node)
549+
print_loc(node)
550+
visit_all(node.comments)
551+
552+
printl("#{node.name} = new")
553+
end
554+
545555
# @override
546556
#: (TypeMember node) -> void
547557
def visit_type_member(node)

lib/rbi/rbs_printer.rb

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -645,19 +645,22 @@ def visit_tenum(node)
645645
# @override
646646
#: (TEnumBlock node) -> void
647647
def visit_tenum_block(node)
648-
node.nodes.each do |child|
649-
child = if child.is_a?(Const) && child.value == "new"
650-
parent = node.parent_scope
651-
Const.new(
652-
child.name,
653-
"T.let(nil, #{parent.is_a?(TEnum) ? parent.name : "T.untyped"})",
654-
comments: child.comments,
655-
)
656-
else
657-
child
658-
end
659-
visit(child)
660-
@previous_node = child
648+
visit_all(node.nodes)
649+
end
650+
651+
# @override
652+
#: (TEnumValue node) -> void
653+
def visit_tenum_value(node)
654+
print_blank_line_before(node)
655+
print_loc(node)
656+
visit_all(node.comments)
657+
658+
t_enum = node.parent_scope&.parent_scope
659+
660+
if t_enum.is_a?(TEnum)
661+
printl("#{node.name}: #{t_enum.name}")
662+
else
663+
printl("#{node.name}: untyped")
661664
end
662665
end
663666

lib/rbi/visitor.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def visit(node)
8888
visit_sig(node)
8989
when SigParam
9090
visit_sig_param(node)
91+
when TEnumValue
92+
visit_tenum_value(node)
9193
when TStructConst
9294
visit_tstruct_const(node)
9395
when TStructProp
@@ -222,6 +224,9 @@ def visit_tenum(node); end
222224
#: (TEnumBlock node) -> void
223225
def visit_tenum_block(node); end
224226

227+
#: (TEnumValue node) -> void
228+
def visit_tenum_value(node); end
229+
225230
#: (Helper node) -> void
226231
def visit_helper(node); end
227232

test/rbi/parser_test.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,14 @@ def baz; end
309309

310310
# Make sure the enums are not parsed as normal classes
311311
enum = tree.nodes.first
312-
assert_instance_of(TEnum, enum.class)
312+
assert_instance_of(TEnum, enum)
313313

314314
block = T.cast(enum, TEnum).nodes.first
315315
assert_instance_of(TEnumBlock, block)
316316

317317
values = T.cast(block, TEnumBlock).nodes
318-
assert(values.all? { |value| value.is_a?(Const) })
318+
assert_equal(3, values.size)
319+
assert_equal(3, values.grep(TEnumValue).size)
319320

320321
assert_equal(rbi, tree.string)
321322
end
@@ -335,7 +336,13 @@ def baz; end
335336

336337
# Make sure the enums are not parsed as normal classes
337338
enum = tree.nodes.first
338-
assert_equal(TEnum, enum.class)
339+
assert_instance_of(TEnum, enum)
340+
341+
block = T.cast(enum, TEnum).nodes.first
342+
assert_instance_of(TEnumBlock, block)
343+
344+
value = T.cast(block, TEnumBlock).nodes.first
345+
assert_instance_of(TEnumValue, value)
339346

340347
assert_equal(rbi, tree.string)
341348
end

0 commit comments

Comments
 (0)