ruby-lsp 0.26.9 → 0.27.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +2 -2
  4. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +8 -8
  5. data/lib/ruby_indexer/ruby_indexer.rb +0 -1
  6. data/lib/ruby_lsp/addon.rb +19 -19
  7. data/lib/ruby_lsp/global_state.rb +11 -2
  8. data/lib/ruby_lsp/internal.rb +6 -1
  9. data/lib/ruby_lsp/listeners/definition.rb +65 -99
  10. data/lib/ruby_lsp/listeners/document_link.rb +4 -0
  11. data/lib/ruby_lsp/listeners/hover.rb +258 -123
  12. data/lib/ruby_lsp/listeners/spec_style.rb +6 -1
  13. data/lib/ruby_lsp/listeners/test_discovery.rb +21 -14
  14. data/lib/ruby_lsp/listeners/test_style.rb +20 -8
  15. data/lib/ruby_lsp/node_context.rb +32 -9
  16. data/lib/ruby_lsp/requests/completion_resolve.rb +9 -13
  17. data/lib/ruby_lsp/requests/discover_tests.rb +5 -41
  18. data/lib/ruby_lsp/requests/hover.rb +2 -5
  19. data/lib/ruby_lsp/requests/on_type_formatting.rb +4 -0
  20. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +66 -22
  21. data/lib/ruby_lsp/requests/references.rb +170 -70
  22. data/lib/ruby_lsp/requests/rename.rb +64 -72
  23. data/lib/ruby_lsp/requests/request.rb +3 -33
  24. data/lib/ruby_lsp/requests/support/common.rb +53 -0
  25. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +82 -46
  26. data/lib/ruby_lsp/requests/workspace_symbol.rb +15 -37
  27. data/lib/ruby_lsp/rubydex/declaration.rb +48 -0
  28. data/lib/ruby_lsp/rubydex/definition.rb +257 -0
  29. data/lib/ruby_lsp/rubydex/reference.rb +21 -0
  30. data/lib/ruby_lsp/server.rb +82 -8
  31. data/lib/ruby_lsp/store.rb +0 -6
  32. data/lib/ruby_lsp/test_helper.rb +3 -0
  33. data/lib/ruby_lsp/type_inferrer.rb +111 -31
  34. metadata +18 -5
  35. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +0 -335
  36. data/lib/ruby_lsp/static_docs.rb +0 -20
  37. data/static_docs/break.md +0 -103
  38. data/static_docs/yield.md +0 -81
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b12b079fa54de3410e0d0ab2db9bf2241c6413c3c61d3ead21d4bbcc9b4e7d6
4
- data.tar.gz: dede13048ef29f79079271c7d20d505160f8fe24d495863e08be96c95207c6bf
3
+ metadata.gz: 11c508848c7c0db2c86807dd05b5de3a0cf33c8d69259cffd34865af8f50d93b
4
+ data.tar.gz: d030d7223e7714008fef42f5b8635b373cf42f88f60e3c22a878dd1e48ed2ee8
5
5
  SHA512:
6
- metadata.gz: 922edf8dadc38fa037d2c157c8e0b9bbbd3c759931ac6cda3070b615a3039597028672e8632507e80689f6a8f6cc793e7a1006a49bba28d72489f541e75f2fc3
7
- data.tar.gz: 046d2d369c16a743f71750a9a6dfed945d8e21b43bb58ad357ce1098fd731dc4e7060ffebcc96e1b78a43a3b2571ac9e31d94dc6c25c380478cb54a979c0f461
6
+ metadata.gz: 23d4677fea98fe4723442e9162c9835ce9813eab354882c9b3cbd45deb4fc9cd81a91d1618cdb8e580c68eeaf840a45cc7271c031b2b4bf559d92a50d64755ec
7
+ data.tar.gz: 1e044d2758e1872a1a94df7f288e8e2ff4b1b4ca2a089db8958acf5830bacd8247086c1c0df167fe072a6586a8391332ceaaa1827add9280e9c42cd3ce96bdf2
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.26.9
1
+ 0.27.0.beta2
@@ -129,7 +129,7 @@ module RubyIndexer
129
129
 
130
130
  if current_owner
131
131
  expression = node.expression
132
- name = (expression.is_a?(Prism::SelfNode) ? "<Class:#{last_name_in_stack}>" : "<Class:#{expression.slice}>")
132
+ name = (expression.is_a?(Prism::SelfNode) ? "<#{last_name_in_stack}>" : "<#{expression.slice}>")
133
133
  real_nesting = Index.actual_nesting(@stack, name)
134
134
 
135
135
  existing_entries = @index[real_nesting.join("::")] #: as Array[Entry::SingletonClass]?
@@ -577,7 +577,7 @@ module RubyIndexer
577
577
 
578
578
  # set the class variable's owner to the attached context when defined within a singleton scope.
579
579
  if owner.is_a?(Entry::SingletonClass)
580
- owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<Class:") }
580
+ owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<") }
581
581
  end
582
582
 
583
583
  @index.add(Entry::ClassVariable.new(
@@ -507,7 +507,7 @@ module RubyIndexer
507
507
  singleton_levels = 0
508
508
 
509
509
  parts.reverse_each do |part|
510
- break unless part.include?("<Class:")
510
+ break unless part.start_with?("<")
511
511
 
512
512
  singleton_levels += 1
513
513
  parts.pop
@@ -551,7 +551,7 @@ module RubyIndexer
551
551
 
552
552
  if nesting.any?
553
553
  singleton_levels.times do
554
- nesting << "<Class:#{nesting.last}>"
554
+ nesting << "<#{nesting.last}>"
555
555
  end
556
556
  end
557
557
 
@@ -616,7 +616,7 @@ module RubyIndexer
616
616
  if class_variables.any?
617
617
  name_parts = owner_name.split("::")
618
618
 
619
- if name_parts.last&.start_with?("<Class:")
619
+ if name_parts.last&.start_with?("<")
620
620
  attached_name = name_parts[0..-2] #: as !nil
621
621
  .join("::")
622
622
  attached_ancestors = linearized_ancestors_of(attached_name)
@@ -707,7 +707,7 @@ module RubyIndexer
707
707
  #: (String name) -> Entry::SingletonClass
708
708
  def existing_or_new_singleton_class(name)
709
709
  *_namespace, unqualified_name = name.split("::")
710
- full_singleton_name = "#{name}::<Class:#{unqualified_name}>"
710
+ full_singleton_name = "#{name}::<#{unqualified_name}>"
711
711
  singleton = self[full_singleton_name]&.first #: as Entry::SingletonClass?
712
712
 
713
713
  unless singleton
@@ -744,7 +744,7 @@ module RubyIndexer
744
744
  def linearized_attached_ancestors(name)
745
745
  name_parts = name.split("::")
746
746
 
747
- if name_parts.last&.start_with?("<Class:")
747
+ if name_parts.last&.start_with?("<")
748
748
  attached_name = name_parts[0..-2] #: as !nil
749
749
  .join("::")
750
750
  linearized_ancestors_of(attached_name)
@@ -866,7 +866,7 @@ module RubyIndexer
866
866
 
867
867
  parent_name_parts = parent_class_name.split("::")
868
868
  singleton_levels.times do
869
- parent_name_parts << "<Class:#{parent_name_parts.last}>"
869
+ parent_name_parts << "<#{parent_name_parts.last}>"
870
870
  end
871
871
 
872
872
  ancestors.concat(linearized_ancestors_of(parent_name_parts.join("::")))
@@ -878,7 +878,7 @@ module RubyIndexer
878
878
  class_class_name_parts = ["Class"]
879
879
 
880
880
  (singleton_levels - 1).times do
881
- class_class_name_parts << "<Class:#{class_class_name_parts.last}>"
881
+ class_class_name_parts << "<#{class_class_name_parts.last}>"
882
882
  end
883
883
 
884
884
  ancestors.concat(linearized_ancestors_of(class_class_name_parts.join("::")))
@@ -892,7 +892,7 @@ module RubyIndexer
892
892
  module_class_name_parts = ["Module"]
893
893
 
894
894
  (singleton_levels - 1).times do
895
- module_class_name_parts << "<Class:#{module_class_name_parts.last}>"
895
+ module_class_name_parts << "<#{module_class_name_parts.last}>"
896
896
  end
897
897
 
898
898
  ancestors.concat(linearized_ancestors_of(module_class_name_parts.join("::")))
@@ -7,7 +7,6 @@ require "did_you_mean"
7
7
  require "ruby_indexer/lib/ruby_indexer/uri"
8
8
  require "ruby_indexer/lib/ruby_indexer/visibility_scope"
9
9
  require "ruby_indexer/lib/ruby_indexer/declaration_listener"
10
- require "ruby_indexer/lib/ruby_indexer/reference_finder"
11
10
  require "ruby_indexer/lib/ruby_indexer/enhancement"
12
11
  require "ruby_indexer/lib/ruby_indexer/index"
13
12
  require "ruby_indexer/lib/ruby_indexer/entry"
@@ -56,26 +56,9 @@ module RubyLsp
56
56
  addon_files = Gem.find_files("ruby_lsp/**/addon.rb")
57
57
 
58
58
  if include_project_addons
59
- project_addons = Dir.glob("#{global_state.workspace_path}/**/ruby_lsp/**/addon.rb")
60
59
  bundle_path = Bundler.bundle_path.to_s
61
- gems_dir = Bundler.bundle_path.join("gems")
62
-
63
- # Create an array of rejection glob patterns to ignore add-ons already discovered through Gem.find_files if
64
- # they are also copied inside the workspace for whatever reason. We received reports of projects having gems
65
- # installed in vendor/bundle despite BUNDLE_PATH pointing elsewhere. Without this mechanism, we will
66
- # double-require the same add-on, potentially for different versions of the same gem, which leads to incorrect
67
- # behavior
68
- reject_glob_patterns = addon_files.map do |path|
69
- relative_gem_path = Pathname.new(path).relative_path_from(gems_dir)
70
- first_part, *parts = relative_gem_path.to_s.split(File::SEPARATOR)
71
- first_part&.gsub!(/-([0-9.]+)$/, "*")
72
- "**/#{first_part}/#{parts.join("/")}"
73
- end
74
-
75
- project_addons.reject! do |path|
76
- path.start_with?(bundle_path) ||
77
- reject_glob_patterns.any? { |pattern| File.fnmatch?(pattern, path, File::Constants::FNM_PATHNAME) }
78
- end
60
+ project_addons = Dir.glob("#{global_state.workspace_path}/**/ruby_lsp/**/addon.rb")
61
+ project_addons.reject! { |path| path.start_with?(bundle_path) || gem_installation_path?(path) }
79
62
 
80
63
  addon_files.concat(project_addons)
81
64
  end
@@ -162,6 +145,23 @@ module RubyLsp
162
145
  "Add-on is not compatible with this version of the Ruby LSP. Skipping its activation"
163
146
  end
164
147
  end
148
+
149
+ private
150
+
151
+ # Checks if a path appears to be inside a versioned gem installation directory (e.g., `rubocop-1.73.0/lib/...`) by
152
+ # looking for a directory segment matching `name-version` before the `lib` component
153
+ #
154
+ #: (String path) -> bool
155
+ def gem_installation_path?(path)
156
+ parts = path.split(%r{[/\\]})
157
+ lib_index = parts.rindex("lib")
158
+ return false unless lib_index
159
+
160
+ prefix = parts[0...lib_index] #: Array[String]?
161
+ return false unless prefix
162
+
163
+ prefix.any? { |part| part.match?(/-\d+(\.\d+)+$/) }
164
+ end
165
165
  end
166
166
 
167
167
  #: -> void
@@ -30,6 +30,9 @@ module RubyLsp
30
30
  #: RubyIndexer::Index
31
31
  attr_reader :index
32
32
 
33
+ #: Rubydex::Graph
34
+ attr_reader :graph
35
+
33
36
  #: Encoding
34
37
  attr_reader :encoding
35
38
 
@@ -58,8 +61,9 @@ module RubyLsp
58
61
  @test_library = "minitest" #: String
59
62
  @has_type_checker = true #: bool
60
63
  @index = RubyIndexer::Index.new #: RubyIndexer::Index
64
+ @graph = Rubydex::Graph.new #: Rubydex::Graph
61
65
  @supported_formatters = {} #: Hash[String, Requests::Support::Formatter]
62
- @type_inferrer = TypeInferrer.new(@index) #: TypeInferrer
66
+ @type_inferrer = TypeInferrer.new(@graph) #: TypeInferrer
63
67
  @addon_settings = {} #: Hash[String, untyped]
64
68
  @top_level_bundle = begin
65
69
  Bundler.with_original_env { Bundler.default_gemfile }
@@ -117,6 +121,7 @@ module RubyLsp
117
121
  all_dependencies = gather_direct_and_indirect_dependencies
118
122
  workspace_uri = options.dig(:workspaceFolders, 0, :uri)
119
123
  @workspace_uri = URI(workspace_uri) if workspace_uri
124
+ @graph.workspace_path = workspace_path
120
125
 
121
126
  specified_formatter = options.dig(:initializationOptions, :formatter)
122
127
  rubocop_has_addon = defined?(::RuboCop::Version::STRING) &&
@@ -189,13 +194,17 @@ module RubyLsp
189
194
 
190
195
  encodings = options.dig(:capabilities, :general, :positionEncodings)
191
196
  @encoding = if !encodings || encodings.empty?
197
+ @graph.encoding = "utf16"
192
198
  Encoding::UTF_16LE
193
199
  elsif encodings.include?(Constant::PositionEncodingKind::UTF8)
200
+ @graph.encoding = "utf8"
194
201
  Encoding::UTF_8
195
202
  elsif encodings.include?(Constant::PositionEncodingKind::UTF16)
203
+ @graph.encoding = "utf16"
196
204
  Encoding::UTF_16LE
197
205
  else
198
- Encoding::UTF_32
206
+ @graph.encoding = "utf32"
207
+ Encoding::UTF_32LE
199
208
  end
200
209
  @index.configuration.encoding = @encoding
201
210
 
@@ -20,6 +20,7 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.5")
20
20
  end
21
21
  require "set"
22
22
  require "strscan"
23
+ require "rubydex"
23
24
  require "prism"
24
25
  require "prism/visitor"
25
26
  require "language_server-protocol"
@@ -30,11 +31,15 @@ require "securerandom"
30
31
  require "shellwords"
31
32
  require "set"
32
33
 
34
+ # Rubydex LSP additions
35
+ require "ruby_lsp/rubydex/declaration"
36
+ require "ruby_lsp/rubydex/definition"
37
+ require "ruby_lsp/rubydex/reference"
38
+
33
39
  require "ruby-lsp"
34
40
  require "ruby_lsp/base_server"
35
41
  require "ruby_indexer/ruby_indexer"
36
42
  require "ruby_lsp/utils"
37
- require "ruby_lsp/static_docs"
38
43
  require "ruby_lsp/scope"
39
44
  require "ruby_lsp/client_capabilities"
40
45
  require "ruby_lsp/global_state"
@@ -12,7 +12,7 @@ module RubyLsp
12
12
  def initialize(response_builder, global_state, language_id, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
13
13
  @response_builder = response_builder
14
14
  @global_state = global_state
15
- @index = global_state.index #: RubyIndexer::Index
15
+ @graph = global_state.graph #: Rubydex::Graph
16
16
  @type_inferrer = global_state.type_inferrer #: TypeInferrer
17
17
  @language_id = language_id
18
18
  @uri = uri
@@ -109,7 +109,7 @@ module RubyLsp
109
109
  name = RubyIndexer::Index.constant_name(node)
110
110
  return if name.nil?
111
111
 
112
- find_in_index(name)
112
+ handle_constant_definition(name)
113
113
  end
114
114
 
115
115
  #: (Prism::ConstantReadNode node) -> void
@@ -117,7 +117,7 @@ module RubyLsp
117
117
  name = RubyIndexer::Index.constant_name(node)
118
118
  return if name.nil?
119
119
 
120
- find_in_index(name)
120
+ handle_constant_definition(name)
121
121
  end
122
122
 
123
123
  #: (Prism::GlobalVariableAndWriteNode node) -> void
@@ -152,32 +152,32 @@ module RubyLsp
152
152
 
153
153
  #: (Prism::InstanceVariableReadNode node) -> void
154
154
  def on_instance_variable_read_node_enter(node)
155
- handle_instance_variable_definition(node.name.to_s)
155
+ handle_variable_definition(node.name.to_s)
156
156
  end
157
157
 
158
158
  #: (Prism::InstanceVariableWriteNode node) -> void
159
159
  def on_instance_variable_write_node_enter(node)
160
- handle_instance_variable_definition(node.name.to_s)
160
+ handle_variable_definition(node.name.to_s)
161
161
  end
162
162
 
163
163
  #: (Prism::InstanceVariableAndWriteNode node) -> void
164
164
  def on_instance_variable_and_write_node_enter(node)
165
- handle_instance_variable_definition(node.name.to_s)
165
+ handle_variable_definition(node.name.to_s)
166
166
  end
167
167
 
168
168
  #: (Prism::InstanceVariableOperatorWriteNode node) -> void
169
169
  def on_instance_variable_operator_write_node_enter(node)
170
- handle_instance_variable_definition(node.name.to_s)
170
+ handle_variable_definition(node.name.to_s)
171
171
  end
172
172
 
173
173
  #: (Prism::InstanceVariableOrWriteNode node) -> void
174
174
  def on_instance_variable_or_write_node_enter(node)
175
- handle_instance_variable_definition(node.name.to_s)
175
+ handle_variable_definition(node.name.to_s)
176
176
  end
177
177
 
178
178
  #: (Prism::InstanceVariableTargetNode node) -> void
179
179
  def on_instance_variable_target_node_enter(node)
180
- handle_instance_variable_definition(node.name.to_s)
180
+ handle_variable_definition(node.name.to_s)
181
181
  end
182
182
 
183
183
  #: (Prism::SuperNode node) -> void
@@ -192,32 +192,32 @@ module RubyLsp
192
192
 
193
193
  #: (Prism::ClassVariableAndWriteNode node) -> void
194
194
  def on_class_variable_and_write_node_enter(node)
195
- handle_class_variable_definition(node.name.to_s)
195
+ handle_variable_definition(node.name.to_s)
196
196
  end
197
197
 
198
198
  #: (Prism::ClassVariableOperatorWriteNode node) -> void
199
199
  def on_class_variable_operator_write_node_enter(node)
200
- handle_class_variable_definition(node.name.to_s)
200
+ handle_variable_definition(node.name.to_s)
201
201
  end
202
202
 
203
203
  #: (Prism::ClassVariableOrWriteNode node) -> void
204
204
  def on_class_variable_or_write_node_enter(node)
205
- handle_class_variable_definition(node.name.to_s)
205
+ handle_variable_definition(node.name.to_s)
206
206
  end
207
207
 
208
208
  #: (Prism::ClassVariableTargetNode node) -> void
209
209
  def on_class_variable_target_node_enter(node)
210
- handle_class_variable_definition(node.name.to_s)
210
+ handle_variable_definition(node.name.to_s)
211
211
  end
212
212
 
213
213
  #: (Prism::ClassVariableReadNode node) -> void
214
214
  def on_class_variable_read_node_enter(node)
215
- handle_class_variable_definition(node.name.to_s)
215
+ handle_variable_definition(node.name.to_s)
216
216
  end
217
217
 
218
218
  #: (Prism::ClassVariableWriteNode node) -> void
219
219
  def on_class_variable_write_node_enter(node)
220
- handle_class_variable_definition(node.name.to_s)
220
+ handle_variable_definition(node.name.to_s)
221
221
  end
222
222
 
223
223
  private
@@ -249,7 +249,7 @@ module RubyLsp
249
249
  return unless surrounding_method
250
250
 
251
251
  handle_method_definition(
252
- surrounding_method,
252
+ surrounding_method.name,
253
253
  @type_inferrer.infer_receiver_type(@node_context),
254
254
  inherited_only: true,
255
255
  )
@@ -257,93 +257,63 @@ module RubyLsp
257
257
 
258
258
  #: (String name) -> void
259
259
  def handle_global_variable_definition(name)
260
- entries = @index[name]
260
+ declaration = @graph[name]
261
+ return unless declaration
261
262
 
262
- return unless entries
263
-
264
- entries.each do |entry|
265
- location = entry.location
266
-
267
- @response_builder << Interface::Location.new(
268
- uri: entry.uri.to_s,
269
- range: Interface::Range.new(
270
- start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
271
- end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
272
- ),
273
- )
274
- end
275
- end
276
-
277
- #: (String name) -> void
278
- def handle_class_variable_definition(name)
279
- type = @type_inferrer.infer_receiver_type(@node_context)
280
- return unless type
281
-
282
- entries = @index.resolve_class_variable(name, type.name)
283
- return unless entries
284
-
285
- entries.each do |entry|
286
- @response_builder << Interface::Location.new(
287
- uri: entry.uri.to_s,
288
- range: range_from_location(entry.location),
289
- )
290
- end
291
- rescue RubyIndexer::Index::NonExistingNamespaceError
292
- # If by any chance we haven't indexed the owner, then there's no way to find the right declaration
263
+ declaration.definitions.each { |definition| @response_builder << definition.to_lsp_selection_location }
293
264
  end
294
265
 
266
+ # Handle class or instance variables. We collect all definitions across the ancestors of the type
267
+ #
295
268
  #: (String name) -> void
296
- def handle_instance_variable_definition(name)
297
- # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
298
- # to provide all features for them
269
+ def handle_variable_definition(name)
270
+ # Sorbet enforces that all variables be declared on typed strict or higher, which means it will be able to
271
+ # provide all features for them
299
272
  return if @sorbet_level.strict?
300
273
 
301
274
  type = @type_inferrer.infer_receiver_type(@node_context)
302
275
  return unless type
303
276
 
304
- entries = @index.resolve_instance_variable(name, type.name)
305
- return unless entries
277
+ owner = @graph[type.name]
278
+ return unless owner.is_a?(Rubydex::Namespace)
306
279
 
307
- entries.each do |entry|
308
- location = entry.location
280
+ owner.ancestors.each do |ancestor|
281
+ member = ancestor.member(name)
282
+ next unless member
309
283
 
310
- @response_builder << Interface::Location.new(
311
- uri: entry.uri.to_s,
312
- range: Interface::Range.new(
313
- start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
314
- end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
315
- ),
316
- )
284
+ member.definitions.each { |definition| @response_builder << definition.to_lsp_selection_location }
317
285
  end
318
- rescue RubyIndexer::Index::NonExistingNamespaceError
319
- # If by any chance we haven't indexed the owner, then there's no way to find the right declaration
320
286
  end
321
287
 
322
288
  #: (String message, TypeInferrer::Type? receiver_type, ?inherited_only: bool) -> void
323
289
  def handle_method_definition(message, receiver_type, inherited_only: false)
324
- methods = if receiver_type
325
- @index.resolve_method(message, receiver_type.name, inherited_only: inherited_only)
290
+ declaration = if receiver_type
291
+ owner = @graph[receiver_type.name]
292
+ owner.find_member("#{message}()", only_inherited: inherited_only) if owner.is_a?(Rubydex::Namespace)
326
293
  end
327
294
 
328
- # If the method doesn't have a receiver, or the guessed receiver doesn't have any matched candidates,
329
- # then we provide a few candidates to jump to
330
- # But we don't want to provide too many candidates, as it can be overwhelming
331
- if receiver_type.nil? || (receiver_type.is_a?(TypeInferrer::GuessedType) && methods.nil?)
332
- methods = @index[message]&.take(MAX_NUMBER_OF_DEFINITION_CANDIDATES_WITHOUT_RECEIVER)
295
+ # If the method doesn't have a receiver, or the guessed receiver doesn't have any matched candidates, then we
296
+ # provide a few candidates to jump to. However, we don't want to provide too many candidates, as it can be
297
+ # overwhelming
298
+ if receiver_type.nil? || (receiver_type.is_a?(TypeInferrer::GuessedType) && declaration.nil?)
299
+ declaration = @graph.search("##{message}()").take(MAX_NUMBER_OF_DEFINITION_CANDIDATES_WITHOUT_RECEIVER)
333
300
  end
334
301
 
335
- return unless methods
302
+ return unless declaration
336
303
 
337
- methods.each do |target_method|
338
- uri = target_method.uri
339
- full_path = uri.full_path
340
- next if @sorbet_level.true_or_higher? && (!full_path || not_in_dependencies?(full_path))
304
+ Array(declaration).each do |decl|
305
+ decl.definitions.each do |definition|
306
+ location = definition.location
307
+ uri = URI(location.uri)
308
+ full_path = uri.full_path
309
+ next if @sorbet_level.true_or_higher? && (!full_path || not_in_dependencies?(full_path))
341
310
 
342
- @response_builder << Interface::LocationLink.new(
343
- target_uri: uri.to_s,
344
- target_range: range_from_location(target_method.location),
345
- target_selection_range: range_from_location(target_method.name_location),
346
- )
311
+ @response_builder << Interface::LocationLink.new(
312
+ target_uri: uri.to_s,
313
+ target_range: definition.to_lsp_selection_range,
314
+ target_selection_range: definition.to_lsp_name_range || definition.to_lsp_selection_range,
315
+ )
316
+ end
347
317
  end
348
318
  end
349
319
 
@@ -351,12 +321,10 @@ module RubyLsp
351
321
  def handle_require_definition(node, message)
352
322
  case message
353
323
  when :require
354
- entry = @index.search_require_paths(node.content).find do |uri|
355
- uri.require_path == node.content
356
- end
324
+ document = @graph.resolve_require_path(node.content, $LOAD_PATH)
357
325
 
358
- if entry
359
- candidate = entry.full_path
326
+ if document
327
+ candidate = URI(document.uri).full_path
360
328
 
361
329
  if candidate
362
330
  @response_builder << Interface::Location.new(
@@ -392,35 +360,33 @@ module RubyLsp
392
360
  constant_name = argument.value
393
361
  return unless constant_name
394
362
 
395
- find_in_index(constant_name)
363
+ handle_constant_definition(constant_name)
396
364
  end
397
365
 
398
366
  #: (String value) -> void
399
- def find_in_index(value)
400
- entries = @index.resolve(value, @node_context.nesting)
401
- return unless entries
367
+ def handle_constant_definition(value)
368
+ declaration = @graph.resolve_constant(value, @node_context.nesting)
369
+ return unless declaration
402
370
 
371
+ # [RUBYDEX] TODO: temporarily commented out until we have the visibility API
372
+ #
403
373
  # We should only allow jumping to the definition of private constants if the constant is defined in the same
404
374
  # namespace as the reference
405
- first_entry = entries.first #: as !nil
406
- return if first_entry.private? && first_entry.name != "#{@node_context.fully_qualified_name}::#{value}"
375
+ #
376
+ # return if declaration.private? && declaration.name != "#{@node_context.fully_qualified_name}::#{value}"
407
377
 
408
- entries.each do |entry|
378
+ declaration.definitions.each do |definition|
409
379
  # If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
410
380
  # additional behavior on top of jumping to RBIs. The only sigil where Sorbet cannot handle constants is typed
411
381
  # ignore
412
- uri = entry.uri
382
+ uri = URI(definition.location.uri)
413
383
  full_path = uri.full_path
414
384
 
415
385
  if !@sorbet_level.ignore? && (!full_path || not_in_dependencies?(full_path))
416
386
  next
417
387
  end
418
388
 
419
- @response_builder << Interface::LocationLink.new(
420
- target_uri: uri.to_s,
421
- target_range: range_from_location(entry.location),
422
- target_selection_range: range_from_location(entry.name_location),
423
- )
389
+ @response_builder << definition.to_lsp_location_link
424
390
  end
425
391
  end
426
392
  end
@@ -21,6 +21,8 @@ module RubyLsp
21
21
 
22
22
  Gem::Specification.stubs.each do |stub|
23
23
  spec = stub.to_spec
24
+ next unless spec
25
+
24
26
  lookup[spec.name] = {}
25
27
  lookup[spec.name][spec.version.to_s] = {}
26
28
 
@@ -31,6 +33,8 @@ module RubyLsp
31
33
 
32
34
  Gem::Specification.default_stubs.each do |stub|
33
35
  spec = stub.to_spec
36
+ next unless spec
37
+
34
38
  lookup[spec.name] = {}
35
39
  lookup[spec.name][spec.version.to_s] = {}
36
40
  prefix_matchers = Regexp.union(spec.require_paths.map do |rp|