@@ -29,6 +29,8 @@ def initialize(location, message)
2929 TopLevelMethodDefinition = _ = Class . new ( Base )
3030 UnusedInlineAnnotation = _ = Class . new ( Base )
3131 AnnotationSyntaxError = _ = Class . new ( Base )
32+ MixinMultipleArguments = _ = Class . new ( Base )
33+ MixinNonConstantModule = _ = Class . new ( Base )
3234 end
3335
3436 def self . parse ( buffer , prism )
@@ -168,6 +170,80 @@ def visit_def_node(node)
168170 end
169171 end
170172
173+ def visit_call_node ( node )
174+ return unless node . receiver . nil? # Only handle top-level calls like include, extend, prepend
175+
176+ case node . name
177+ when :include , :extend , :prepend
178+ return if skip_node? ( node )
179+
180+ case current = current_module
181+ when AST ::Ruby ::Declarations ::ClassDecl , AST ::Ruby ::Declarations ::ModuleDecl
182+ parse_mixin_call ( node )
183+ end
184+ else
185+ visit_child_nodes ( node )
186+ end
187+ end
188+
189+ private
190+
191+ def parse_mixin_call ( node )
192+ # Check for multiple arguments
193+ if node . arguments && node . arguments . arguments . length > 1
194+ diagnostics << Diagnostic ::MixinMultipleArguments . new (
195+ rbs_location ( node . location ) ,
196+ "Mixing multiple modules with one call is not supported"
197+ )
198+ return
199+ end
200+
201+ # Check for missing arguments
202+ unless node . arguments && node . arguments . arguments . length == 1
203+ # This shouldn't happen in valid Ruby code, but handle it gracefully
204+ return
205+ end
206+
207+ first_arg = node . arguments . arguments . first
208+
209+ # Check if the argument is a constant
210+ unless module_name = constant_as_type_name ( first_arg )
211+ diagnostics << Diagnostic ::MixinNonConstantModule . new (
212+ rbs_location ( first_arg . location ) ,
213+ "Module name must be a constant"
214+ )
215+ return
216+ end
217+
218+ # Look for type application annotation in trailing comments
219+ # For single-line calls like "include Bar #[String]", the annotation is trailing
220+ trailing_block = comments . trailing_block! ( node . location )
221+ annotation = nil
222+
223+ if trailing_block
224+ case trailing_annotation = trailing_block . trailing_annotation ( [ ] )
225+ when AST ::Ruby ::Annotations ::TypeApplicationAnnotation
226+ annotation = trailing_annotation
227+ else
228+ report_unused_annotation ( trailing_annotation )
229+ end
230+ end
231+
232+ # Create the appropriate member based on the method name
233+ member = case node . name
234+ when :include
235+ AST ::Ruby ::Members ::IncludeMember . new ( buffer , node , module_name , annotation )
236+ when :extend
237+ AST ::Ruby ::Members ::ExtendMember . new ( buffer , node , module_name , annotation )
238+ when :prepend
239+ AST ::Ruby ::Members ::PrependMember . new ( buffer , node , module_name , annotation )
240+ else
241+ raise "Unexpected mixin method: #{ node . name } "
242+ end
243+
244+ current_module! . members << member
245+ end
246+
171247 def insert_declaration ( decl )
172248 if current_module
173249 current_module . members << decl
0 commit comments