@@ -12,9 +12,12 @@ def initialize(ruby_contents, file:, positional_names:)
1212 super ( ruby_contents , file : file )
1313
1414 @positional_names = positional_names #: bool
15- @nesting = [ ] #: Array[Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode]
1615 @last_sigs = [ ] #: Array[[Prism::CallNode, RBI::Sig]]
16+ @class_annotations = [ ] #: Array[Prism::CallNode]
1717 @type_members = [ ] #: Array[String]
18+ @extend_t_helpers = [ ] #: Array[Prism::CallNode]
19+ @extend_t_generics = [ ] #: Array[Prism::CallNode]
20+ @seen_mixes_in_class_methods = false #: bool
1821 end
1922
2023 # @override
@@ -71,7 +74,9 @@ def visit_call_node(node)
7174 when "extend"
7275 visit_extend ( node )
7376 when "abstract!" , "interface!" , "sealed!" , "final!" , "requires_ancestor"
74- visit_class_annotation ( node )
77+ @class_annotations << node
78+ when "mixes_in_class_methods"
79+ @seen_mixes_in_class_methods = true
7580 else
7681 super
7782 end
@@ -97,19 +102,39 @@ def visit_constant_write_node(node)
97102
98103 #: (Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode) { -> void } -> void
99104 def visit_scope ( node , &block )
100- @nesting << node
105+ old_class_annotations = @class_annotations
106+ @class_annotations = [ ]
101107 old_type_members = @type_members
102108 @type_members = [ ]
109+ old_extend_t_helpers = @extend_t_helpers
110+ @extend_t_helpers = [ ]
111+ old_extend_t_generics = @extend_t_generics
112+ @extend_t_generics = [ ]
113+ old_seen_mixes_in_class_methods = @seen_mixes_in_class_methods
114+ @seen_mixes_in_class_methods = false
103115
104116 yield
105117
118+ delete_extend_t_generics
119+
106120 if @type_members . any?
107121 indent = " " * node . location . start_column
108122 @rewriter << Source ::Insert . new ( node . location . start_offset , "#: [#{ @type_members . join ( ", " ) } ]\n #{ indent } " )
109123 end
110124
125+ unless @seen_mixes_in_class_methods
126+ delete_extend_t_helpers
127+ end
128+
129+ @class_annotations . each do |call |
130+ apply_class_annotation ( node , call )
131+ end
132+
133+ @class_annotations = old_class_annotations
111134 @type_members = old_type_members
112- @nesting . pop
135+ @extend_t_helpers = old_extend_t_helpers
136+ @extend_t_generics = old_extend_t_generics
137+ @seen_mixes_in_class_methods = old_seen_mixes_in_class_methods
113138 end
114139
115140 #: (Prism::CallNode) -> void
@@ -160,16 +185,17 @@ def visit_extend(node)
160185
161186 arg = node . arguments &.arguments &.first
162187 return unless arg . is_a? ( Prism ::ConstantPathNode )
163- return unless arg . slice . match? ( /^(::)?T::Helpers$/ ) || arg . slice . match? ( /^(::)?T::Generic$/ )
164188
165- from = adjust_to_line_start ( node . location . start_offset )
166- to = adjust_to_line_end ( node . location . end_offset )
167- to = adjust_to_new_line ( to )
168- @rewriter << Source ::Delete . new ( from , to )
189+ case arg . slice
190+ when /^(::)?T::Helpers$/
191+ @extend_t_helpers << node
192+ when /^(::)?T::Generic$/
193+ @extend_t_generics << node
194+ end
169195 end
170196
171- #: (Prism::CallNode node ) -> void
172- def visit_class_annotation ( node )
197+ #: (Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode, Prism::CallNode ) -> void
198+ def apply_class_annotation ( parent , node )
173199 unless node . message == "abstract!" || node . message == "interface!" || node . message == "sealed!" ||
174200 node . message == "final!" || node . message == "requires_ancestor"
175201 raise Error , "Expected abstract!, interface!, sealed!, final!, or requires_ancestor"
@@ -178,18 +204,17 @@ def visit_class_annotation(node)
178204 return unless node . receiver . nil? || node . receiver . is_a? ( Prism ::SelfNode )
179205 return unless node . arguments . nil?
180206
181- klass = @nesting . last #: as Prism::Node
182- indent = " " * klass . location . start_column
207+ indent = " " * parent . location . start_column
183208
184209 case node . message
185210 when "abstract!"
186- @rewriter << Source ::Insert . new ( klass . location . start_offset , "# @abstract\n #{ indent } " )
211+ @rewriter << Source ::Insert . new ( parent . location . start_offset , "# @abstract\n #{ indent } " )
187212 when "interface!"
188- @rewriter << Source ::Insert . new ( klass . location . start_offset , "# @interface\n #{ indent } " )
213+ @rewriter << Source ::Insert . new ( parent . location . start_offset , "# @interface\n #{ indent } " )
189214 when "sealed!"
190- @rewriter << Source ::Insert . new ( klass . location . start_offset , "# @sealed\n #{ indent } " )
215+ @rewriter << Source ::Insert . new ( parent . location . start_offset , "# @sealed\n #{ indent } " )
191216 when "final!"
192- @rewriter << Source ::Insert . new ( klass . location . start_offset , "# @final\n #{ indent } " )
217+ @rewriter << Source ::Insert . new ( parent . location . start_offset , "# @final\n #{ indent } " )
193218 when "requires_ancestor"
194219 block = node . block
195220 return unless block . is_a? ( Prism ::BlockNode )
@@ -200,7 +225,7 @@ def visit_class_annotation(node)
200225
201226 arg = body . body . first #: as Prism::Node
202227 srb_type = RBI ::Type . parse_node ( arg )
203- @rewriter << Source ::Insert . new ( klass . location . start_offset , "# @requires_ancestor: #{ srb_type . rbs_string } \n #{ indent } " )
228+ @rewriter << Source ::Insert . new ( parent . location . start_offset , "# @requires_ancestor: #{ srb_type . rbs_string } \n #{ indent } " )
204229 end
205230
206231 from = adjust_to_line_start ( node . location . start_offset )
@@ -287,6 +312,30 @@ def build_type_member_string(node)
287312
288313 type_member
289314 end
315+
316+ #: -> void
317+ def delete_extend_t_helpers
318+ @extend_t_helpers . each do |helper |
319+ from = adjust_to_line_start ( helper . location . start_offset )
320+ to = adjust_to_line_end ( helper . location . end_offset )
321+ to = adjust_to_new_line ( to )
322+ @rewriter << Source ::Delete . new ( from , to )
323+ end
324+
325+ @extend_t_helpers . clear
326+ end
327+
328+ #: -> void
329+ def delete_extend_t_generics
330+ @extend_t_generics . each do |generic |
331+ from = adjust_to_line_start ( generic . location . start_offset )
332+ to = adjust_to_line_end ( generic . location . end_offset )
333+ to = adjust_to_new_line ( to )
334+ @rewriter << Source ::Delete . new ( from , to )
335+ end
336+
337+ @extend_t_generics . clear
338+ end
290339 end
291340 end
292341 end
0 commit comments