@@ -176,45 +176,79 @@ def location_for(iseq)
176
176
Location . new ( code_location [ 0 ] , code_location [ 1 ] )
177
177
end
178
178
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
+
179
202
def index_iseq ( iseq , file_comments )
180
203
results = [ ]
181
204
queue = [ [ iseq , [ ] ] ]
182
205
183
206
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 |
185
209
next unless insn . is_a? ( Array )
186
210
187
211
case insn [ 0 ]
188
212
when :defineclass
189
213
_ , 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
190
224
191
225
if flags == VM_DEFINECLASS_TYPE_SINGLETON_CLASS
192
226
# At the moment, we don't support singletons that aren't
193
227
# defined on self. We could, but it would require more
194
228
# emulation.
195
- if current_iseq [ 13 ] [ index - 2 ] != [ :putself ]
229
+ if insns [ index - 2 ] != [ :putself ]
196
230
raise NotImplementedError ,
197
231
"singleton class with non-self receiver"
198
232
end
199
233
elsif flags & VM_DEFINECLASS_TYPE_MODULE > 0
200
234
location = location_for ( class_iseq )
201
235
results << ModuleDefinition . new (
202
- current_nesting ,
236
+ next_nesting ,
203
237
name ,
204
238
location ,
205
239
EntryComments . new ( file_comments , location )
206
240
)
207
241
else
208
242
location = location_for ( class_iseq )
209
243
results << ClassDefinition . new (
210
- current_nesting ,
244
+ next_nesting ,
211
245
name ,
212
246
location ,
213
247
EntryComments . new ( file_comments , location )
214
248
)
215
249
end
216
250
217
- queue << [ class_iseq , current_nesting + [ name ] ]
251
+ queue << [ class_iseq , next_nesting ]
218
252
when :definemethod
219
253
location = location_for ( insn [ 2 ] )
220
254
results << MethodDefinition . new (
@@ -259,24 +293,36 @@ def initialize
259
293
260
294
visit_methods do
261
295
def visit_class ( node )
262
- name = visit ( node . constant ) . to_sym
296
+ names = visit ( node . constant )
297
+ nesting << names
298
+
263
299
location =
264
300
Location . new ( node . location . start_line , node . location . start_column )
265
301
266
302
results << ClassDefinition . new (
267
303
nesting . dup ,
268
- name ,
304
+ names . last ,
269
305
location ,
270
306
comments_for ( node )
271
307
)
272
308
273
- nesting << name
274
309
super
275
310
nesting . pop
276
311
end
277
312
278
313
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
280
326
end
281
327
282
328
def visit_def ( node )
@@ -302,18 +348,19 @@ def visit_def(node)
302
348
end
303
349
304
350
def visit_module ( node )
305
- name = visit ( node . constant ) . to_sym
351
+ names = visit ( node . constant )
352
+ nesting << names
353
+
306
354
location =
307
355
Location . new ( node . location . start_line , node . location . start_column )
308
356
309
357
results << ModuleDefinition . new (
310
358
nesting . dup ,
311
- name ,
359
+ names . last ,
312
360
location ,
313
361
comments_for ( node )
314
362
)
315
363
316
- nesting << name
317
364
super
318
365
nesting . pop
319
366
end
@@ -327,6 +374,10 @@ def visit_statements(node)
327
374
@statements = node
328
375
super
329
376
end
377
+
378
+ def visit_var_ref ( node )
379
+ node . value . value . to_sym
380
+ end
330
381
end
331
382
332
383
private
0 commit comments