ruby-lsp 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +10 -9
  4. data/exe/ruby-lsp-check +5 -5
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
  6. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +131 -23
  7. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
  8. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
  9. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
  10. data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
  11. data/lib/ruby_indexer/ruby_indexer.rb +1 -1
  12. data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
  13. data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -6
  14. data/lib/ruby_indexer/test/configuration_test.rb +116 -51
  15. data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
  16. data/lib/ruby_indexer/test/index_test.rb +72 -43
  17. data/lib/ruby_indexer/test/method_test.rb +80 -0
  18. data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
  19. data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
  20. data/lib/ruby_indexer/test/test_case.rb +2 -2
  21. data/lib/ruby_indexer/test/uri_test.rb +72 -0
  22. data/lib/ruby_lsp/addon.rb +9 -0
  23. data/lib/ruby_lsp/base_server.rb +15 -6
  24. data/lib/ruby_lsp/document.rb +10 -1
  25. data/lib/ruby_lsp/global_state.rb +1 -1
  26. data/lib/ruby_lsp/internal.rb +1 -1
  27. data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
  28. data/lib/ruby_lsp/listeners/completion.rb +73 -4
  29. data/lib/ruby_lsp/listeners/definition.rb +73 -17
  30. data/lib/ruby_lsp/listeners/document_symbol.rb +49 -5
  31. data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
  32. data/lib/ruby_lsp/listeners/hover.rb +57 -0
  33. data/lib/ruby_lsp/requests/completion.rb +6 -0
  34. data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
  35. data/lib/ruby_lsp/requests/definition.rb +6 -0
  36. data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
  37. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
  38. data/lib/ruby_lsp/requests/rename.rb +14 -4
  39. data/lib/ruby_lsp/requests/support/common.rb +1 -5
  40. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
  41. data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
  42. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  43. data/lib/ruby_lsp/server.rb +42 -7
  44. data/lib/ruby_lsp/setup_bundler.rb +54 -46
  45. data/lib/ruby_lsp/test_helper.rb +45 -11
  46. data/lib/ruby_lsp/type_inferrer.rb +22 -0
  47. data/lib/ruby_lsp/utils.rb +3 -0
  48. metadata +7 -8
  49. data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e48cef95e466e2a75943921fc08ede1a449e07096e44078ca063bdbee6d3c54b
4
- data.tar.gz: c0ce6a0636645674e9e9a87219124b622b1280420c14c4bd12f8f0f0aafc3f32
3
+ metadata.gz: 3792653083ea45143ce56ff51f68ced5217a52e9172c2cb33e03d012eda30ee8
4
+ data.tar.gz: 7d798218889b1add42189e08013a3503d9140a6504144fd0edfd8de00827c7f0
5
5
  SHA512:
6
- metadata.gz: 89d02237ecce7e784bb5275ba4d5fc30b64981ea337b078f3117037b98d8f734e0d7e6266078e76023125dd52bbcb6ded8d04fdac1c29eb8292fd29e401cece4
7
- data.tar.gz: 7245d82a481bd9e6a56d0cce9ad03796bd1a6d9e770beb5632fcaf7669ab0af9e9c0c95f0b671d844231af718add21b98011665ac3355fab5647ab12378b60bf
6
+ metadata.gz: ec313c0971ed544bfb14904105345d8a4843e8aa4eeefaccbcbdb69e40ff2da2f618b4d95f89cf86ed51a90a9e3f2cb7aca93d56dca352de6f1ac2b4aff29dfe
7
+ data.tar.gz: 1fb2034291a4ca052d91c03095dcea32165dd2deaeafdbda59dfd67142d6380fcf9f1306879b9b516c8ba14605223042625fca5ecc1b7b9eb2137c0777ebc32f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.22.0
1
+ 0.23.0
data/exe/ruby-lsp CHANGED
@@ -64,7 +64,7 @@ if ENV["BUNDLE_GEMFILE"].nil?
64
64
  # which gives us the opportunity to control which specs are activated and enter degraded mode if any gems failed to
65
65
  # install rather than failing to boot the server completely
66
66
  if options[:launcher]
67
- command = +File.expand_path("ruby-lsp-launcher", __dir__)
67
+ command = +"#{Gem.ruby} #{File.expand_path("ruby-lsp-launcher", __dir__)}"
68
68
  command << " --debug" if options[:debug]
69
69
  exit exec(command)
70
70
  end
@@ -78,13 +78,14 @@ if ENV["BUNDLE_GEMFILE"].nil?
78
78
  exit(78)
79
79
  end
80
80
 
81
- base_bundle = if env["BUNDLER_VERSION"]
82
- "bundle _#{env["BUNDLER_VERSION"]}_"
83
- else
84
- "bundle"
81
+ bundler_path = File.join(Gem.default_bindir, "bundle")
82
+ base_command = (File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
83
+
84
+ if env["BUNDLER_VERSION"]
85
+ base_command << " _#{env["BUNDLER_VERSION"]}_"
85
86
  end
86
87
 
87
- exit exec(env, "#{base_bundle} exec ruby-lsp #{original_args.join(" ")}".strip)
88
+ exit exec(env, "#{base_command} exec ruby-lsp #{original_args.join(" ")}".strip)
88
89
  end
89
90
 
90
91
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
@@ -139,9 +140,9 @@ if options[:doctor]
139
140
 
140
141
  puts "Globbing for indexable files"
141
142
 
142
- index.configuration.indexables.each do |indexable|
143
- puts "indexing: #{indexable.full_path}"
144
- index.index_single(indexable)
143
+ index.configuration.indexable_uris.each do |uri|
144
+ puts "indexing: #{uri}"
145
+ index.index_file(uri)
145
146
  end
146
147
  return
147
148
  end
data/exe/ruby-lsp-check CHANGED
@@ -44,14 +44,14 @@ puts "\n"
44
44
  puts "Verifying that indexing executes successfully. This may take a while..."
45
45
 
46
46
  index = RubyIndexer::Index.new
47
- indexables = index.configuration.indexables
47
+ uris = index.configuration.indexable_uris
48
48
 
49
- indexables.each_with_index do |indexable, i|
50
- index.index_single(indexable)
49
+ uris.each_with_index do |uri, i|
50
+ index.index_file(uri)
51
51
  rescue => e
52
- errors[indexable.full_path] = e
52
+ errors[uri.full_path] = e
53
53
  ensure
54
- print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
54
+ print("\033[M\033[0KIndexed #{i + 1}/#{uris.length}") unless ENV["CI"]
55
55
  end
56
56
  puts "\n"
57
57
 
@@ -81,8 +81,8 @@ module RubyIndexer
81
81
  .then { |dirs| File.join(@workspace_path, "{#{dirs.join(",")}}/**/*") }
82
82
  end
83
83
 
84
- sig { returns(T::Array[IndexablePath]) }
85
- def indexables
84
+ sig { returns(T::Array[URI::Generic]) }
85
+ def indexable_uris
86
86
  excluded_gems = @excluded_gems - @included_gems
87
87
  locked_gems = Bundler.locked_gems&.specs
88
88
 
@@ -107,12 +107,12 @@ module RubyIndexer
107
107
  [included_path, relative_path]
108
108
  end
109
109
 
110
- indexables = T.let([], T::Array[IndexablePath])
110
+ uris = T.let([], T::Array[URI::Generic])
111
111
 
112
112
  # Handle top level files separately. The path below is an optimization to prevent descending down directories that
113
113
  # are going to be excluded anyway, so we need to handle top level scripts separately
114
114
  Dir.glob(File.join(@workspace_path, "*.rb"), flags).each do |path|
115
- indexables << IndexablePath.new(nil, path)
115
+ uris << URI::Generic.from_path(path: path)
116
116
  end
117
117
 
118
118
  # Add user specified patterns
@@ -134,7 +134,7 @@ module RubyIndexer
134
134
  load_path_entry = $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
135
135
  end
136
136
 
137
- indexables << IndexablePath.new(load_path_entry, path)
137
+ uris << URI::Generic.from_path(path: path, load_path_entry: load_path_entry)
138
138
  end
139
139
  end
140
140
  end
@@ -150,9 +150,9 @@ module RubyIndexer
150
150
  end
151
151
 
152
152
  # Remove user specified patterns
153
- indexables.reject! do |indexable|
153
+ uris.reject! do |indexable|
154
154
  excluded_patterns.any? do |pattern|
155
- File.fnmatch?(pattern, indexable.full_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
155
+ File.fnmatch?(pattern, T.must(indexable.full_path), File::FNM_PATHNAME | File::FNM_EXTGLOB)
156
156
  end
157
157
  end
158
158
 
@@ -182,14 +182,14 @@ module RubyIndexer
182
182
 
183
183
  if pathname.directory?
184
184
  # If the default_path is a directory, we index all the Ruby files in it
185
- indexables.concat(
185
+ uris.concat(
186
186
  Dir.glob(File.join(default_path, "**", "*.rb"), File::FNM_PATHNAME | File::FNM_EXTGLOB).map! do |path|
187
- IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
187
+ URI::Generic.from_path(path: path, load_path_entry: RbConfig::CONFIG["rubylibdir"])
188
188
  end,
189
189
  )
190
190
  elsif pathname.extname == ".rb"
191
191
  # If the default_path is a Ruby file, we index it
192
- indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
192
+ uris << URI::Generic.from_path(path: default_path, load_path_entry: RbConfig::CONFIG["rubylibdir"])
193
193
  end
194
194
  end
195
195
 
@@ -204,10 +204,12 @@ module RubyIndexer
204
204
  # duplicates or accidentally ignoring exclude patterns
205
205
  next if spec.full_gem_path == @workspace_path
206
206
 
207
- indexables.concat(
207
+ uris.concat(
208
208
  spec.require_paths.flat_map do |require_path|
209
209
  load_path_entry = File.join(spec.full_gem_path, require_path)
210
- Dir.glob(File.join(load_path_entry, "**", "*.rb")).map! { |path| IndexablePath.new(load_path_entry, path) }
210
+ Dir.glob(File.join(load_path_entry, "**", "*.rb")).map! do |path|
211
+ URI::Generic.from_path(path: path, load_path_entry: load_path_entry)
212
+ end
211
213
  end,
212
214
  )
213
215
  rescue Gem::MissingSpecError
@@ -216,8 +218,8 @@ module RubyIndexer
216
218
  # just ignore if they're missing
217
219
  end
218
220
 
219
- indexables.uniq!(&:full_path)
220
- indexables
221
+ uris.uniq!(&:to_s)
222
+ uris
221
223
  end
222
224
 
223
225
  sig { returns(Regexp) }
@@ -271,6 +273,15 @@ module RubyIndexer
271
273
  end
272
274
 
273
275
  others.concat(this_gem.to_spec.dependencies) if this_gem
276
+ others.concat(
277
+ others.filter_map do |d|
278
+ d.to_spec&.dependencies
279
+ rescue Gem::MissingSpecError
280
+ nil
281
+ end.flatten,
282
+ )
283
+ others.uniq!
284
+ others.map!(&:name)
274
285
 
275
286
  excluded.each do |dependency|
276
287
  next unless dependency.runtime?
@@ -279,12 +290,7 @@ module RubyIndexer
279
290
  next unless spec
280
291
 
281
292
  spec.dependencies.each do |transitive_dependency|
282
- # If the transitive dependency is included in other groups, skip it
283
- next if others.any? { |d| d.name == transitive_dependency.name }
284
-
285
- # If the transitive dependency is included as a transitive dependency of a gem outside of the development
286
- # group, skip it
287
- next if others.any? { |d| d.to_spec&.dependencies&.include?(transitive_dependency) }
293
+ next if others.include?(transitive_dependency.name)
288
294
 
289
295
  excluded << transitive_dependency
290
296
  end
@@ -16,13 +16,13 @@ module RubyIndexer
16
16
  index: Index,
17
17
  dispatcher: Prism::Dispatcher,
18
18
  parse_result: Prism::ParseResult,
19
- file_path: String,
19
+ uri: URI::Generic,
20
20
  collect_comments: T::Boolean,
21
21
  ).void
22
22
  end
23
- def initialize(index, dispatcher, parse_result, file_path, collect_comments: false)
23
+ def initialize(index, dispatcher, parse_result, uri, collect_comments: false)
24
24
  @index = index
25
- @file_path = file_path
25
+ @uri = uri
26
26
  @enhancements = T.let(Enhancement.all(self), T::Array[Enhancement])
27
27
  @visibility_stack = T.let([Entry::Visibility::PUBLIC], T::Array[Entry::Visibility])
28
28
  @comments_by_line = T.let(
@@ -80,6 +80,11 @@ module RubyIndexer
80
80
  :on_instance_variable_or_write_node_enter,
81
81
  :on_instance_variable_target_node_enter,
82
82
  :on_alias_method_node_enter,
83
+ :on_class_variable_and_write_node_enter,
84
+ :on_class_variable_operator_write_node_enter,
85
+ :on_class_variable_or_write_node_enter,
86
+ :on_class_variable_target_node_enter,
87
+ :on_class_variable_write_node_enter,
83
88
  )
84
89
  end
85
90
 
@@ -154,7 +159,7 @@ module RubyIndexer
154
159
  else
155
160
  entry = Entry::SingletonClass.new(
156
161
  real_nesting,
157
- @file_path,
162
+ @uri,
158
163
  Location.from_prism_location(node.location, @code_units_cache),
159
164
  Location.from_prism_location(expression.location, @code_units_cache),
160
165
  collect_comments(node),
@@ -282,13 +287,16 @@ module RubyIndexer
282
287
  @visibility_stack.push(Entry::Visibility::PRIVATE)
283
288
  when :module_function
284
289
  handle_module_function(node)
290
+ when :private_class_method
291
+ @visibility_stack.push(Entry::Visibility::PRIVATE)
292
+ handle_private_class_method(node)
285
293
  end
286
294
 
287
295
  @enhancements.each do |enhancement|
288
296
  enhancement.on_call_node_enter(node)
289
297
  rescue StandardError => e
290
298
  @indexing_errors << <<~MSG
291
- Indexing error in #{@file_path} with '#{enhancement.class.name}' on call node enter enhancement: #{e.message}
299
+ Indexing error in #{@uri} with '#{enhancement.class.name}' on call node enter enhancement: #{e.message}
292
300
  MSG
293
301
  end
294
302
  end
@@ -297,7 +305,7 @@ module RubyIndexer
297
305
  def on_call_node_leave(node)
298
306
  message = node.name
299
307
  case message
300
- when :public, :protected, :private
308
+ when :public, :protected, :private, :private_class_method
301
309
  # We want to restore the visibility stack when we leave a method definition with a visibility modifier
302
310
  # e.g. `private def foo; end`
303
311
  if node.arguments&.arguments&.first&.is_a?(Prism::DefNode)
@@ -309,7 +317,7 @@ module RubyIndexer
309
317
  enhancement.on_call_node_leave(node)
310
318
  rescue StandardError => e
311
319
  @indexing_errors << <<~MSG
312
- Indexing error in #{@file_path} with '#{enhancement.class.name}' on call node leave enhancement: #{e.message}
320
+ Indexing error in #{@uri} with '#{enhancement.class.name}' on call node leave enhancement: #{e.message}
313
321
  MSG
314
322
  end
315
323
  end
@@ -324,7 +332,7 @@ module RubyIndexer
324
332
  when nil
325
333
  @index.add(Entry::Method.new(
326
334
  method_name,
327
- @file_path,
335
+ @uri,
328
336
  Location.from_prism_location(node.location, @code_units_cache),
329
337
  Location.from_prism_location(node.name_loc, @code_units_cache),
330
338
  comments,
@@ -340,7 +348,7 @@ module RubyIndexer
340
348
 
341
349
  @index.add(Entry::Method.new(
342
350
  method_name,
343
- @file_path,
351
+ @uri,
344
352
  Location.from_prism_location(node.location, @code_units_cache),
345
353
  Location.from_prism_location(node.name_loc, @code_units_cache),
346
354
  comments,
@@ -424,13 +432,38 @@ module RubyIndexer
424
432
  method_name,
425
433
  node.old_name.slice,
426
434
  @owner_stack.last,
427
- @file_path,
435
+ @uri,
428
436
  Location.from_prism_location(node.new_name.location, @code_units_cache),
429
437
  comments,
430
438
  ),
431
439
  )
432
440
  end
433
441
 
442
+ sig { params(node: Prism::ClassVariableAndWriteNode).void }
443
+ def on_class_variable_and_write_node_enter(node)
444
+ handle_class_variable(node, node.name_loc)
445
+ end
446
+
447
+ sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
448
+ def on_class_variable_operator_write_node_enter(node)
449
+ handle_class_variable(node, node.name_loc)
450
+ end
451
+
452
+ sig { params(node: Prism::ClassVariableOrWriteNode).void }
453
+ def on_class_variable_or_write_node_enter(node)
454
+ handle_class_variable(node, node.name_loc)
455
+ end
456
+
457
+ sig { params(node: Prism::ClassVariableTargetNode).void }
458
+ def on_class_variable_target_node_enter(node)
459
+ handle_class_variable(node, node.location)
460
+ end
461
+
462
+ sig { params(node: Prism::ClassVariableWriteNode).void }
463
+ def on_class_variable_write_node_enter(node)
464
+ handle_class_variable(node, node.name_loc)
465
+ end
466
+
434
467
  sig do
435
468
  params(
436
469
  name: String,
@@ -445,7 +478,7 @@ module RubyIndexer
445
478
 
446
479
  @index.add(Entry::Method.new(
447
480
  name,
448
- @file_path,
481
+ @uri,
449
482
  location,
450
483
  location,
451
484
  comments,
@@ -469,7 +502,7 @@ module RubyIndexer
469
502
 
470
503
  entry = Entry::Module.new(
471
504
  actual_nesting(name),
472
- @file_path,
505
+ @uri,
473
506
  location,
474
507
  name_loc,
475
508
  comments,
@@ -491,7 +524,7 @@ module RubyIndexer
491
524
  nesting = name_or_nesting.is_a?(Array) ? name_or_nesting : actual_nesting(name_or_nesting)
492
525
  entry = Entry::Class.new(
493
526
  nesting,
494
- @file_path,
527
+ @uri,
495
528
  Location.from_prism_location(full_location, @code_units_cache),
496
529
  Location.from_prism_location(name_location, @code_units_cache),
497
530
  comments,
@@ -543,12 +576,48 @@ module RubyIndexer
543
576
 
544
577
  @index.add(Entry::GlobalVariable.new(
545
578
  name,
546
- @file_path,
579
+ @uri,
547
580
  Location.from_prism_location(loc, @code_units_cache),
548
581
  comments,
549
582
  ))
550
583
  end
551
584
 
585
+ sig do
586
+ params(
587
+ node: T.any(
588
+ Prism::ClassVariableAndWriteNode,
589
+ Prism::ClassVariableOperatorWriteNode,
590
+ Prism::ClassVariableOrWriteNode,
591
+ Prism::ClassVariableTargetNode,
592
+ Prism::ClassVariableWriteNode,
593
+ ),
594
+ loc: Prism::Location,
595
+ ).void
596
+ end
597
+ def handle_class_variable(node, loc)
598
+ name = node.name.to_s
599
+ # Ignore incomplete class variable names, which aren't valid Ruby syntax.
600
+ # This could occur if the code is in an incomplete or temporary state.
601
+ return if name == "@@"
602
+
603
+ comments = collect_comments(node)
604
+
605
+ owner = @owner_stack.last
606
+
607
+ # set the class variable's owner to the attached context when defined within a singleton scope.
608
+ if owner.is_a?(Entry::SingletonClass)
609
+ owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<Class:") }
610
+ end
611
+
612
+ @index.add(Entry::ClassVariable.new(
613
+ name,
614
+ @uri,
615
+ Location.from_prism_location(loc, @code_units_cache),
616
+ comments,
617
+ owner,
618
+ ))
619
+ end
620
+
552
621
  sig do
553
622
  params(
554
623
  node: T.any(
@@ -575,7 +644,7 @@ module RubyIndexer
575
644
 
576
645
  @index.add(Entry::InstanceVariable.new(
577
646
  name,
578
- @file_path,
647
+ @uri,
579
648
  Location.from_prism_location(loc, @code_units_cache),
580
649
  collect_comments(node),
581
650
  owner,
@@ -639,7 +708,7 @@ module RubyIndexer
639
708
  new_name_value,
640
709
  old_name_value,
641
710
  @owner_stack.last,
642
- @file_path,
711
+ @uri,
643
712
  Location.from_prism_location(new_name.location, @code_units_cache),
644
713
  comments,
645
714
  ),
@@ -675,7 +744,7 @@ module RubyIndexer
675
744
  value.slice,
676
745
  @stack.dup,
677
746
  name,
678
- @file_path,
747
+ @uri,
679
748
  Location.from_prism_location(node.location, @code_units_cache),
680
749
  comments,
681
750
  )
@@ -688,7 +757,7 @@ module RubyIndexer
688
757
  value.name.to_s,
689
758
  @stack.dup,
690
759
  name,
691
- @file_path,
760
+ @uri,
692
761
  Location.from_prism_location(node.location, @code_units_cache),
693
762
  comments,
694
763
  )
@@ -699,14 +768,14 @@ module RubyIndexer
699
768
  value.target.slice,
700
769
  @stack.dup,
701
770
  name,
702
- @file_path,
771
+ @uri,
703
772
  Location.from_prism_location(node.location, @code_units_cache),
704
773
  comments,
705
774
  )
706
775
  else
707
776
  Entry::Constant.new(
708
777
  name,
709
- @file_path,
778
+ @uri,
710
779
  Location.from_prism_location(node.location, @code_units_cache),
711
780
  comments,
712
781
  )
@@ -778,7 +847,7 @@ module RubyIndexer
778
847
  if reader
779
848
  @index.add(Entry::Accessor.new(
780
849
  name,
781
- @file_path,
850
+ @uri,
782
851
  Location.from_prism_location(loc, @code_units_cache),
783
852
  comments,
784
853
  current_visibility,
@@ -790,7 +859,7 @@ module RubyIndexer
790
859
 
791
860
  @index.add(Entry::Accessor.new(
792
861
  "#{name}=",
793
- @file_path,
862
+ @uri,
794
863
  Location.from_prism_location(loc, @code_units_cache),
795
864
  comments,
796
865
  current_visibility,
@@ -863,7 +932,7 @@ module RubyIndexer
863
932
  location = Location.from_prism_location(argument.location, @code_units_cache)
864
933
  @index.add(Entry::Method.new(
865
934
  method_name,
866
- @file_path,
935
+ @uri,
867
936
  location,
868
937
  location,
869
938
  collect_comments(node)&.concat(entry.comments),
@@ -875,6 +944,45 @@ module RubyIndexer
875
944
  end
876
945
  end
877
946
 
947
+ sig { params(node: Prism::CallNode).void }
948
+ def handle_private_class_method(node)
949
+ node.arguments&.arguments&.each do |argument|
950
+ string_or_symbol_nodes = case argument
951
+ when Prism::StringNode, Prism::SymbolNode
952
+ [argument]
953
+ when Prism::ArrayNode
954
+ argument.elements
955
+ else
956
+ []
957
+ end
958
+
959
+ unless string_or_symbol_nodes.empty?
960
+ # pop the visibility off since there isn't a method definition following `private_class_method`
961
+ @visibility_stack.pop
962
+ end
963
+
964
+ string_or_symbol_nodes.each do |string_or_symbol_node|
965
+ method_name = case string_or_symbol_node
966
+ when Prism::StringNode
967
+ string_or_symbol_node.content
968
+ when Prism::SymbolNode
969
+ string_or_symbol_node.value
970
+ end
971
+ next unless method_name
972
+
973
+ owner_name = @owner_stack.last&.name
974
+ next unless owner_name
975
+
976
+ entries = @index.resolve_method(method_name, @index.existing_or_new_singleton_class(owner_name).name)
977
+ next unless entries
978
+
979
+ entries.each do |entry|
980
+ entry.visibility = Entry::Visibility::PRIVATE
981
+ end
982
+ end
983
+ end
984
+ end
985
+
878
986
  sig { returns(Entry::Visibility) }
879
987
  def current_visibility
880
988
  T.must(@visibility_stack.last)