@@ -176,45 +176,79 @@ def location_for(iseq)
176176 Location . new ( code_location [ 0 ] , code_location [ 1 ] )
177177 end
178178
179+ def find_constant_path ( insns , index )
180+ insn = insns [ index ]
181+
182+ if insn . is_a? ( Array ) && insn [ 0 ] == :opt_getconstant_path
183+ # In this case we're on Ruby 3.2+ and we have an opt_getconstant_path
184+ # instruction, so we already know all of the symbols in the nesting.
185+ insn [ 1 ]
186+ elsif insn . is_a? ( Symbol ) && insn . match? ( /\A label_\d +/ )
187+ # Otherwise, if we have a label then this is very likely the
188+ # destination of an opt_getinlinecache instruction, in which case
189+ # we'll walk backwards to grab up all of the constants.
190+ names = [ ]
191+
192+ index -= 1
193+ until insns [ index ] [ 0 ] == :opt_getinlinecache
194+ names . unshift ( insns [ index ] [ 1 ] ) if insns [ index ] [ 0 ] == :getconstant
195+ index -= 1
196+ end
197+
198+ names
199+ end
200+ end
201+
179202 def index_iseq ( iseq , file_comments )
180203 results = [ ]
181204 queue = [ [ iseq , [ ] ] ]
182205
183206 while ( current_iseq , current_nesting = queue . shift )
184- current_iseq [ 13 ] . each_with_index do |insn , index |
207+ insns = current_iseq [ 13 ]
208+ insns . each_with_index do |insn , index |
185209 next unless insn . is_a? ( Array )
186210
187211 case insn [ 0 ]
188212 when :defineclass
189213 _ , name , class_iseq , flags = insn
214+ next_nesting = current_nesting . dup
215+
216+ if ( nesting = find_constant_path ( insns , index - 2 ) )
217+ # If there is a constant path in the class name, then we need to
218+ # handle that by updating the nesting.
219+ next_nesting << ( nesting << name )
220+ else
221+ # Otherwise we'll add the class name to the nesting.
222+ next_nesting << [ name ]
223+ end
190224
191225 if flags == VM_DEFINECLASS_TYPE_SINGLETON_CLASS
192226 # At the moment, we don't support singletons that aren't
193227 # defined on self. We could, but it would require more
194228 # emulation.
195- if current_iseq [ 13 ] [ index - 2 ] != [ :putself ]
229+ if insns [ index - 2 ] != [ :putself ]
196230 raise NotImplementedError ,
197231 "singleton class with non-self receiver"
198232 end
199233 elsif flags & VM_DEFINECLASS_TYPE_MODULE > 0
200234 location = location_for ( class_iseq )
201235 results << ModuleDefinition . new (
202- current_nesting ,
236+ next_nesting ,
203237 name ,
204238 location ,
205239 EntryComments . new ( file_comments , location )
206240 )
207241 else
208242 location = location_for ( class_iseq )
209243 results << ClassDefinition . new (
210- current_nesting ,
244+ next_nesting ,
211245 name ,
212246 location ,
213247 EntryComments . new ( file_comments , location )
214248 )
215249 end
216250
217- queue << [ class_iseq , current_nesting + [ name ] ]
251+ queue << [ class_iseq , next_nesting ]
218252 when :definemethod
219253 location = location_for ( insn [ 2 ] )
220254 results << MethodDefinition . new (
@@ -259,24 +293,36 @@ def initialize
259293
260294 visit_methods do
261295 def visit_class ( node )
262- name = visit ( node . constant ) . to_sym
296+ names = visit ( node . constant )
297+ nesting << names
298+
263299 location =
264300 Location . new ( node . location . start_line , node . location . start_column )
265301
266302 results << ClassDefinition . new (
267303 nesting . dup ,
268- name ,
304+ names . last ,
269305 location ,
270306 comments_for ( node )
271307 )
272308
273- nesting << name
274309 super
275310 nesting . pop
276311 end
277312
278313 def visit_const_ref ( node )
279- node . constant . value
314+ [ node . constant . value . to_sym ]
315+ end
316+
317+ def visit_const_path_ref ( node )
318+ names =
319+ if node . parent . is_a? ( ConstPathRef )
320+ visit ( node . parent )
321+ else
322+ [ visit ( node . parent ) ]
323+ end
324+
325+ names << node . constant . value . to_sym
280326 end
281327
282328 def visit_def ( node )
@@ -302,18 +348,19 @@ def visit_def(node)
302348 end
303349
304350 def visit_module ( node )
305- name = visit ( node . constant ) . to_sym
351+ names = visit ( node . constant )
352+ nesting << names
353+
306354 location =
307355 Location . new ( node . location . start_line , node . location . start_column )
308356
309357 results << ModuleDefinition . new (
310358 nesting . dup ,
311- name ,
359+ names . last ,
312360 location ,
313361 comments_for ( node )
314362 )
315363
316- nesting << name
317364 super
318365 nesting . pop
319366 end
@@ -327,6 +374,10 @@ def visit_statements(node)
327374 @statements = node
328375 super
329376 end
377+
378+ def visit_var_ref ( node )
379+ node . value . value . to_sym
380+ end
330381 end
331382
332383 private
0 commit comments