ruby-lsp 0.23.11 → 0.26.6

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +46 -22
  7. data/exe/ruby-lsp-test-exec +6 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +85 -118
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +159 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +130 -253
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +189 -285
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +31 -59
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_lsp/addon.rb +88 -86
  22. data/lib/ruby_lsp/base_server.rb +79 -65
  23. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  24. data/lib/ruby_lsp/document.rb +205 -104
  25. data/lib/ruby_lsp/erb_document.rb +45 -47
  26. data/lib/ruby_lsp/global_state.rb +134 -86
  27. data/lib/ruby_lsp/internal.rb +8 -3
  28. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  29. data/lib/ruby_lsp/listeners/completion.rb +81 -76
  30. data/lib/ruby_lsp/listeners/definition.rb +78 -72
  31. data/lib/ruby_lsp/listeners/document_highlight.rb +149 -151
  32. data/lib/ruby_lsp/listeners/document_link.rb +93 -86
  33. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  34. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  35. data/lib/ruby_lsp/listeners/hover.rb +109 -117
  36. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  37. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  38. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  39. data/lib/ruby_lsp/listeners/spec_style.rb +231 -0
  40. data/lib/ruby_lsp/listeners/test_discovery.rb +107 -0
  41. data/lib/ruby_lsp/listeners/test_style.rb +207 -95
  42. data/lib/ruby_lsp/node_context.rb +12 -39
  43. data/lib/ruby_lsp/rbs_document.rb +10 -11
  44. data/lib/ruby_lsp/requests/code_action_resolve.rb +92 -66
  45. data/lib/ruby_lsp/requests/code_actions.rb +34 -31
  46. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  47. data/lib/ruby_lsp/requests/completion.rb +8 -21
  48. data/lib/ruby_lsp/requests/completion_resolve.rb +14 -12
  49. data/lib/ruby_lsp/requests/definition.rb +8 -20
  50. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  51. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  52. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  53. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  54. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  55. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  56. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  57. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +139 -0
  58. data/lib/ruby_lsp/requests/hover.rb +12 -25
  59. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  60. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  61. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  62. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  63. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  64. data/lib/ruby_lsp/requests/references.rb +17 -57
  65. data/lib/ruby_lsp/requests/rename.rb +27 -51
  66. data/lib/ruby_lsp/requests/request.rb +13 -25
  67. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  68. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  69. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  70. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  71. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  72. data/lib/ruby_lsp/requests/support/common.rb +23 -61
  73. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  74. data/lib/ruby_lsp/requests/support/package_url.rb +414 -0
  75. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  76. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  77. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
  78. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  79. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  80. data/lib/ruby_lsp/requests/support/source_uri.rb +22 -33
  81. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  82. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  83. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  84. data/lib/ruby_lsp/requests/workspace_symbol.rb +24 -16
  85. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  86. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  87. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  88. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  89. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  90. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  91. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  92. data/lib/ruby_lsp/ruby_document.rb +32 -98
  93. data/lib/ruby_lsp/scope.rb +7 -11
  94. data/lib/ruby_lsp/scripts/compose_bundle.rb +7 -5
  95. data/lib/ruby_lsp/server.rb +305 -198
  96. data/lib/ruby_lsp/setup_bundler.rb +160 -97
  97. data/lib/ruby_lsp/static_docs.rb +12 -7
  98. data/lib/ruby_lsp/store.rb +21 -49
  99. data/lib/ruby_lsp/test_helper.rb +3 -16
  100. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +241 -0
  101. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  102. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  103. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  104. data/lib/ruby_lsp/utils.rb +138 -93
  105. data/static_docs/break.md +103 -0
  106. metadata +15 -34
  107. data/lib/ruby_indexer/test/class_variables_test.rb +0 -140
  108. data/lib/ruby_indexer/test/classes_and_modules_test.rb +0 -745
  109. data/lib/ruby_indexer/test/configuration_test.rb +0 -239
  110. data/lib/ruby_indexer/test/constant_test.rb +0 -402
  111. data/lib/ruby_indexer/test/enhancements_test.rb +0 -325
  112. data/lib/ruby_indexer/test/global_variable_test.rb +0 -49
  113. data/lib/ruby_indexer/test/index_test.rb +0 -2186
  114. data/lib/ruby_indexer/test/instance_variables_test.rb +0 -240
  115. data/lib/ruby_indexer/test/method_test.rb +0 -947
  116. data/lib/ruby_indexer/test/prefix_tree_test.rb +0 -150
  117. data/lib/ruby_indexer/test/rbs_indexer_test.rb +0 -386
  118. data/lib/ruby_indexer/test/reference_finder_test.rb +0 -330
  119. data/lib/ruby_indexer/test/test_case.rb +0 -51
  120. data/lib/ruby_indexer/test/uri_test.rb +0 -72
  121. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -3,8 +3,6 @@
3
3
 
4
4
  module RubyIndexer
5
5
  class Index
6
- extend T::Sig
7
-
8
6
  class UnresolvableAliasError < StandardError; end
9
7
  class NonExistingNamespaceError < StandardError; end
10
8
  class IndexNotEmptyError < StandardError; end
@@ -12,16 +10,17 @@ module RubyIndexer
12
10
  # The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
13
11
  ENTRY_SIMILARITY_THRESHOLD = 0.7
14
12
 
15
- sig { returns(Configuration) }
13
+ #: Configuration
16
14
  attr_reader :configuration
17
15
 
18
- class << self
19
- extend T::Sig
16
+ #: bool
17
+ attr_reader :initial_indexing_completed
20
18
 
19
+ class << self
21
20
  # Returns the real nesting of a constant name taking into account top level
22
21
  # references that may be included anywhere in the name or nesting where that
23
22
  # constant was found
24
- sig { params(stack: T::Array[String], name: T.nilable(String)).returns(T::Array[String]) }
23
+ #: (Array[String] stack, String? name) -> Array[String]
25
24
  def actual_nesting(stack, name)
26
25
  nesting = name ? stack + [name] : stack
27
26
  corrected_nesting = []
@@ -37,22 +36,10 @@ module RubyIndexer
37
36
 
38
37
  # Returns the unresolved name for a constant reference including all parts of a constant path, or `nil` if the
39
38
  # constant contains dynamic or incomplete parts
40
- sig do
41
- params(
42
- node: T.any(
43
- Prism::ConstantPathNode,
44
- Prism::ConstantReadNode,
45
- Prism::ConstantPathTargetNode,
46
- Prism::CallNode,
47
- Prism::MissingNode,
48
- ),
49
- ).returns(T.nilable(String))
50
- end
39
+ #: (Prism::Node) -> String?
51
40
  def constant_name(node)
52
41
  case node
53
- when Prism::CallNode, Prism::MissingNode
54
- nil
55
- else
42
+ when Prism::ConstantPathNode, Prism::ConstantReadNode, Prism::ConstantPathTargetNode
56
43
  node.full_name
57
44
  end
58
45
  rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
@@ -61,17 +48,17 @@ module RubyIndexer
61
48
  end
62
49
  end
63
50
 
64
- sig { void }
51
+ #: -> void
65
52
  def initialize
66
53
  # Holds all entries in the index using the following format:
67
54
  # {
68
55
  # "Foo" => [#<Entry::Class>, #<Entry::Class>],
69
56
  # "Foo::Bar" => [#<Entry::Class>],
70
57
  # }
71
- @entries = T.let({}, T::Hash[String, T::Array[Entry]])
58
+ @entries = {} #: Hash[String, Array[Entry]]
72
59
 
73
60
  # Holds all entries in the index using a prefix tree for searching based on prefixes to provide autocompletion
74
- @entries_tree = T.let(PrefixTree[T::Array[Entry]].new, PrefixTree[T::Array[Entry]])
61
+ @entries_tree = PrefixTree.new #: PrefixTree[Array[Entry]]
75
62
 
76
63
  # Holds references to where entries where discovered so that we can easily delete them
77
64
  # {
@@ -79,32 +66,29 @@ module RubyIndexer
79
66
  # "file:///my/project/bar.rb" => [#<Entry::Class>],
80
67
  # "untitled:Untitled-1" => [#<Entry::Class>],
81
68
  # }
82
- @uris_to_entries = T.let({}, T::Hash[String, T::Array[Entry]])
69
+ @uris_to_entries = {} #: Hash[String, Array[Entry]]
83
70
 
84
71
  # Holds all require paths for every indexed item so that we can provide autocomplete for requires
85
- @require_paths_tree = T.let(PrefixTree[URI::Generic].new, PrefixTree[URI::Generic])
72
+ @require_paths_tree = PrefixTree.new #: PrefixTree[URI::Generic]
86
73
 
87
74
  # Holds the linearized ancestors list for every namespace
88
- @ancestors = T.let({}, T::Hash[String, T::Array[String]])
75
+ @ancestors = {} #: Hash[String, Array[String]]
89
76
 
90
77
  # Map of module name to included hooks that have to be executed when we include the given module
91
- @included_hooks = T.let(
92
- {},
93
- T::Hash[String, T::Array[T.proc.params(index: Index, base: Entry::Namespace).void]],
94
- )
78
+ @included_hooks = {} #: Hash[String, Array[^(Index index, Entry::Namespace base) -> void]]
95
79
 
96
- @configuration = T.let(RubyIndexer::Configuration.new, Configuration)
80
+ @configuration = RubyIndexer::Configuration.new #: Configuration
97
81
 
98
- @initial_indexing_completed = T.let(false, T::Boolean)
82
+ @initial_indexing_completed = false #: bool
99
83
  end
100
84
 
101
85
  # Register an included `hook` that will be executed when `module_name` is included into any namespace
102
- sig { params(module_name: String, hook: T.proc.params(index: Index, base: Entry::Namespace).void).void }
86
+ #: (String module_name) { (Index index, Entry::Namespace base) -> void } -> void
103
87
  def register_included_hook(module_name, &hook)
104
88
  (@included_hooks[module_name] ||= []) << hook
105
89
  end
106
90
 
107
- sig { params(uri: URI::Generic, skip_require_paths_tree: T::Boolean).void }
91
+ #: (URI::Generic uri, ?skip_require_paths_tree: bool) -> void
108
92
  def delete(uri, skip_require_paths_tree: false)
109
93
  key = uri.to_s
110
94
  # For each constant discovered in `path`, delete the associated entry from the index. If there are no entries
@@ -134,37 +118,34 @@ module RubyIndexer
134
118
  @require_paths_tree.delete(require_path) if require_path
135
119
  end
136
120
 
137
- sig { params(entry: Entry, skip_prefix_tree: T::Boolean).void }
121
+ #: (Entry entry, ?skip_prefix_tree: bool) -> void
138
122
  def add(entry, skip_prefix_tree: false)
139
123
  name = entry.name
140
124
 
141
125
  (@entries[name] ||= []) << entry
142
126
  (@uris_to_entries[entry.uri.to_s] ||= []) << entry
143
- @entries_tree.insert(name, T.must(@entries[name])) unless skip_prefix_tree
127
+
128
+ unless skip_prefix_tree
129
+ @entries_tree.insert(
130
+ name,
131
+ @entries[name], #: as !nil
132
+ )
133
+ end
144
134
  end
145
135
 
146
- sig { params(fully_qualified_name: String).returns(T.nilable(T::Array[Entry])) }
136
+ #: (String fully_qualified_name) -> Array[Entry]?
147
137
  def [](fully_qualified_name)
148
138
  @entries[fully_qualified_name.delete_prefix("::")]
149
139
  end
150
140
 
151
- sig { params(query: String).returns(T::Array[URI::Generic]) }
141
+ #: (String query) -> Array[URI::Generic]
152
142
  def search_require_paths(query)
153
143
  @require_paths_tree.search(query)
154
144
  end
155
145
 
156
146
  # Searches for a constant based on an unqualified name and returns the first possible match regardless of whether
157
147
  # there are more possible matching entries
158
- sig do
159
- params(
160
- name: String,
161
- ).returns(T.nilable(T::Array[T.any(
162
- Entry::Namespace,
163
- Entry::ConstantAlias,
164
- Entry::UnresolvedConstantAlias,
165
- Entry::Constant,
166
- )]))
167
- end
148
+ #: (String name) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
168
149
  def first_unqualified_const(name)
169
150
  # Look for an exact match first
170
151
  _name, entries = @entries.find do |const_name, _entries|
@@ -178,15 +159,7 @@ module RubyIndexer
178
159
  end
179
160
  end
180
161
 
181
- T.cast(
182
- entries,
183
- T.nilable(T::Array[T.any(
184
- Entry::Namespace,
185
- Entry::ConstantAlias,
186
- Entry::UnresolvedConstantAlias,
187
- Entry::Constant,
188
- )]),
189
- )
162
+ entries #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
190
163
  end
191
164
 
192
165
  # Searches entries in the index based on an exact prefix, intended for providing autocomplete. All possible matches
@@ -202,7 +175,7 @@ module RubyIndexer
202
175
  # [#<Entry::Class name="Foo::Baz">],
203
176
  # ]
204
177
  # ```
205
- sig { params(query: String, nesting: T.nilable(T::Array[String])).returns(T::Array[T::Array[Entry]]) }
178
+ #: (String query, ?Array[String]? nesting) -> Array[Array[Entry]]
206
179
  def prefix_search(query, nesting = nil)
207
180
  unless nesting
208
181
  results = @entries_tree.search(query)
@@ -211,7 +184,8 @@ module RubyIndexer
211
184
  end
212
185
 
213
186
  results = nesting.length.downto(0).flat_map do |i|
214
- prefix = T.must(nesting[0...i]).join("::")
187
+ prefix = nesting[0...i] #: as !nil
188
+ .join("::")
215
189
  namespaced_query = prefix.empty? ? query : "#{prefix}::#{query}"
216
190
  @entries_tree.search(namespaced_query)
217
191
  end
@@ -221,12 +195,13 @@ module RubyIndexer
221
195
  end
222
196
 
223
197
  # Fuzzy searches index entries based on Jaro-Winkler similarity. If no query is provided, all entries are returned
224
- sig { params(query: T.nilable(String)).returns(T::Array[Entry]) }
225
- def fuzzy_search(query)
198
+ #: (String? query) ?{ (Entry) -> bool? } -> Array[Entry]
199
+ def fuzzy_search(query, &condition)
226
200
  unless query
227
201
  entries = @entries.filter_map do |_name, entries|
228
202
  next if entries.first.is_a?(Entry::SingletonClass)
229
203
 
204
+ entries = entries.select(&condition) if condition
230
205
  entries
231
206
  end
232
207
 
@@ -238,6 +213,9 @@ module RubyIndexer
238
213
  results = @entries.filter_map do |name, entries|
239
214
  next if entries.first.is_a?(Entry::SingletonClass)
240
215
 
216
+ entries = entries.select(&condition) if condition
217
+ next if entries.empty?
218
+
241
219
  similarity = DidYouMean::JaroWinkler.distance(name.gsub("::", "").downcase, normalized_query)
242
220
  [entries, -similarity] if similarity > ENTRY_SIMILARITY_THRESHOLD
243
221
  end
@@ -245,12 +223,7 @@ module RubyIndexer
245
223
  results.flat_map(&:first)
246
224
  end
247
225
 
248
- sig do
249
- params(
250
- name: T.nilable(String),
251
- receiver_name: String,
252
- ).returns(T::Array[T.any(Entry::Member, Entry::MethodAlias)])
253
- end
226
+ #: (String? name, String receiver_name) -> Array[(Entry::Member | Entry::MethodAlias)]
254
227
  def method_completion_candidates(name, receiver_name)
255
228
  ancestors = linearized_ancestors_of(receiver_name)
256
229
 
@@ -293,29 +266,11 @@ module RubyIndexer
293
266
  completion_items.values.map!(&:first)
294
267
  end
295
268
 
296
- sig do
297
- params(
298
- name: String,
299
- nesting: T::Array[String],
300
- ).returns(T::Array[T::Array[T.any(
301
- Entry::Constant,
302
- Entry::ConstantAlias,
303
- Entry::Namespace,
304
- Entry::UnresolvedConstantAlias,
305
- )]])
306
- end
269
+ #: (String name, Array[String] nesting) -> Array[Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]]
307
270
  def constant_completion_candidates(name, nesting)
308
271
  # If we have a top level reference, then we don't need to include completions inside the current nesting
309
272
  if name.start_with?("::")
310
- return T.cast(
311
- @entries_tree.search(name.delete_prefix("::")),
312
- T::Array[T::Array[T.any(
313
- Entry::Constant,
314
- Entry::ConstantAlias,
315
- Entry::Namespace,
316
- Entry::UnresolvedConstantAlias,
317
- )]],
318
- )
273
+ return @entries_tree.search(name.delete_prefix("::")) #: as Array[Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]]
319
274
  end
320
275
 
321
276
  # Otherwise, we have to include every possible constant the user might be referring to. This is essentially the
@@ -326,7 +281,8 @@ module RubyIndexer
326
281
 
327
282
  # Constants defined in enclosing scopes
328
283
  nesting.length.downto(1) do |i|
329
- namespace = T.must(nesting[0...i]).join("::")
284
+ namespace = nesting[0...i] #: as !nil
285
+ .join("::")
330
286
  entries.concat(@entries_tree.search("#{namespace}::#{name}"))
331
287
  end
332
288
 
@@ -339,16 +295,19 @@ module RubyIndexer
339
295
 
340
296
  # Top level constants
341
297
  entries.concat(@entries_tree.search(name))
298
+
299
+ # Filter only constants since methods may have names that look like constants
300
+ entries.select! do |definitions|
301
+ definitions.select! do |entry|
302
+ entry.is_a?(Entry::Constant) || entry.is_a?(Entry::ConstantAlias) ||
303
+ entry.is_a?(Entry::Namespace) || entry.is_a?(Entry::UnresolvedConstantAlias)
304
+ end
305
+
306
+ definitions.any?
307
+ end
308
+
342
309
  entries.uniq!
343
- T.cast(
344
- entries,
345
- T::Array[T::Array[T.any(
346
- Entry::Constant,
347
- Entry::ConstantAlias,
348
- Entry::Namespace,
349
- Entry::UnresolvedConstantAlias,
350
- )]],
351
- )
310
+ entries #: as Array[Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]]
352
311
  end
353
312
 
354
313
  # Resolve a constant to its declaration based on its name and the nesting where the reference was found. Parameter
@@ -358,17 +317,7 @@ module RubyIndexer
358
317
  # nesting: the nesting structure where the reference was found (e.g.: ["Foo", "Bar"])
359
318
  # seen_names: this parameter should not be used by consumers of the api. It is used to avoid infinite recursion when
360
319
  # resolving circular references
361
- sig do
362
- params(
363
- name: String,
364
- nesting: T::Array[String],
365
- seen_names: T::Array[String],
366
- ).returns(T.nilable(T::Array[T.any(
367
- Entry::Namespace,
368
- Entry::ConstantAlias,
369
- Entry::UnresolvedConstantAlias,
370
- )]))
371
- end
320
+ #: (String name, Array[String] nesting, ?Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
372
321
  def resolve(name, nesting, seen_names = [])
373
322
  # If we have a top level reference, then we just search for it straight away ignoring the nesting
374
323
  if name.start_with?("::")
@@ -404,12 +353,7 @@ module RubyIndexer
404
353
  # Index all files for the given URIs, which defaults to what is configured. A block can be used to track and control
405
354
  # indexing progress. That block is invoked with the current progress percentage and should return `true` to continue
406
355
  # indexing or `false` to stop indexing.
407
- sig do
408
- params(
409
- uris: T::Array[URI::Generic],
410
- block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
411
- ).void
412
- end
356
+ #: (?uris: Array[URI::Generic]) ?{ (Integer progress) -> bool } -> void
413
357
  def index_all(uris: @configuration.indexable_uris, &block)
414
358
  # When troubleshooting an indexing issue, e.g. through irb, it's not obvious that `index_all` will augment the
415
359
  # existing index values, meaning it may contain 'stale' entries. This check ensures that the user is aware of this
@@ -419,8 +363,6 @@ module RubyIndexer
419
363
  "The index is not empty. To prevent invalid entries, `index_all` can only be called once."
420
364
  end
421
365
 
422
- @initial_indexing_completed = true
423
-
424
366
  RBSIndexer.new(self).index_ruby_core
425
367
  # Calculate how many paths are worth 1% of progress
426
368
  progress_step = (uris.length / 100.0).ceil
@@ -433,9 +375,11 @@ module RubyIndexer
433
375
 
434
376
  index_file(uri, collect_comments: false)
435
377
  end
378
+
379
+ @initial_indexing_completed = true
436
380
  end
437
381
 
438
- sig { params(uri: URI::Generic, source: String, collect_comments: T::Boolean).void }
382
+ #: (URI::Generic uri, String source, ?collect_comments: bool) -> void
439
383
  def index_single(uri, source, collect_comments: true)
440
384
  dispatcher = Prism::Dispatcher.new
441
385
 
@@ -457,9 +401,10 @@ module RubyIndexer
457
401
  end
458
402
 
459
403
  # Indexes a File URI by reading the contents from disk
460
- sig { params(uri: URI::Generic, collect_comments: T::Boolean).void }
404
+ #: (URI::Generic uri, ?collect_comments: bool) -> void
461
405
  def index_file(uri, collect_comments: true)
462
- index_single(uri, File.read(T.must(uri.full_path)), collect_comments: collect_comments)
406
+ path = uri.full_path #: as !nil
407
+ index_single(uri, File.read(path), collect_comments: collect_comments)
463
408
  rescue Errno::EISDIR, Errno::ENOENT
464
409
  # If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
465
410
  # it
@@ -475,14 +420,18 @@ module RubyIndexer
475
420
  # If we find an alias, then we want to follow its target. In the same example, if `Foo::Bar` is an alias to
476
421
  # `Something::Else`, then we first discover `Something::Else::Baz`. But `Something::Else::Baz` might contain other
477
422
  # aliases, so we have to invoke `follow_aliased_namespace` again to check until we only return a real name
478
- sig { params(name: String, seen_names: T::Array[String]).returns(String) }
423
+ #: (String name, ?Array[String] seen_names) -> String
479
424
  def follow_aliased_namespace(name, seen_names = [])
480
425
  parts = name.split("::")
481
426
  real_parts = []
482
427
 
483
428
  (parts.length - 1).downto(0) do |i|
484
- current_name = T.must(parts[0..i]).join("::")
485
- entry = @entries[current_name]&.first
429
+ current_name = parts[0..i] #: as !nil
430
+ .join("::")
431
+
432
+ entry = unless seen_names.include?(current_name)
433
+ @entries[current_name]&.first
434
+ end
486
435
 
487
436
  case entry
488
437
  when Entry::ConstantAlias
@@ -498,7 +447,9 @@ module RubyIndexer
498
447
  target = resolved.target
499
448
  return follow_aliased_namespace("#{target}::#{real_parts.join("::")}", seen_names)
500
449
  else
501
- real_parts.unshift(T.must(parts[i]))
450
+ real_parts.unshift(
451
+ parts[i], #: as !nil
452
+ )
502
453
  end
503
454
  end
504
455
 
@@ -508,14 +459,7 @@ module RubyIndexer
508
459
  # Attempts to find methods for a resolved fully qualified receiver name. Do not provide the `seen_names` parameter
509
460
  # as it is used only internally to prevent infinite loops when resolving circular aliases
510
461
  # Returns `nil` if the method does not exist on that receiver
511
- sig do
512
- params(
513
- method_name: String,
514
- receiver_name: String,
515
- seen_names: T::Array[String],
516
- inherited_only: T::Boolean,
517
- ).returns(T.nilable(T::Array[T.any(Entry::Member, Entry::MethodAlias)]))
518
- end
462
+ #: (String method_name, String receiver_name, ?Array[String] seen_names, ?inherited_only: bool) -> Array[(Entry::Member | Entry::MethodAlias)]?
519
463
  def resolve_method(method_name, receiver_name, seen_names = [], inherited_only: false)
520
464
  method_entries = self[method_name]
521
465
  return unless method_entries
@@ -553,7 +497,7 @@ module RubyIndexer
553
497
  # module that prepends another module, then the prepend module appears before the included module.
554
498
  #
555
499
  # The order of ancestors is [linearized_prepends, self, linearized_includes, linearized_superclass]
556
- sig { params(fully_qualified_name: String).returns(T::Array[String]) }
500
+ #: (String fully_qualified_name) -> Array[String]
557
501
  def linearized_ancestors_of(fully_qualified_name)
558
502
  # If we already computed the ancestors for this namespace, return it straight away
559
503
  cached_ancestors = @ancestors[fully_qualified_name]
@@ -602,11 +546,12 @@ module RubyIndexer
602
546
 
603
547
  # The original nesting where we discovered this namespace, so that we resolve the correct names of the
604
548
  # included/prepended/extended modules and parent classes
605
- nesting = T.must(namespaces.first).nesting.flat_map { |n| n.split("::") }
549
+ nesting = namespaces.first #: as !nil
550
+ .nesting.flat_map { |n| n.split("::") }
606
551
 
607
552
  if nesting.any?
608
553
  singleton_levels.times do
609
- nesting << "<Class:#{T.must(nesting.last)}>"
554
+ nesting << "<Class:#{nesting.last}>"
610
555
  end
611
556
  end
612
557
 
@@ -631,9 +576,9 @@ module RubyIndexer
631
576
 
632
577
  # Resolves an instance variable name for a given owner name. This method will linearize the ancestors of the owner
633
578
  # and find inherited instance variables as well
634
- sig { params(variable_name: String, owner_name: String).returns(T.nilable(T::Array[Entry::InstanceVariable])) }
579
+ #: (String variable_name, String owner_name) -> Array[Entry::InstanceVariable]?
635
580
  def resolve_instance_variable(variable_name, owner_name)
636
- entries = T.cast(self[variable_name], T.nilable(T::Array[Entry::InstanceVariable]))
581
+ entries = self[variable_name] #: as Array[Entry::InstanceVariable]?
637
582
  return unless entries
638
583
 
639
584
  ancestors = linearized_ancestors_of(owner_name)
@@ -642,7 +587,7 @@ module RubyIndexer
642
587
  entries.select { |e| ancestors.include?(e.owner&.name) }
643
588
  end
644
589
 
645
- sig { params(variable_name: String, owner_name: String).returns(T.nilable(T::Array[Entry::ClassVariable])) }
590
+ #: (String variable_name, String owner_name) -> Array[Entry::ClassVariable]?
646
591
  def resolve_class_variable(variable_name, owner_name)
647
592
  entries = self[variable_name]&.grep(Entry::ClassVariable)
648
593
  return unless entries&.any?
@@ -655,11 +600,9 @@ module RubyIndexer
655
600
 
656
601
  # Returns a list of possible candidates for completion of instance variables for a given owner name. The name must
657
602
  # include the `@` prefix
658
- sig do
659
- params(name: String, owner_name: String).returns(T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
660
- end
603
+ #: (String name, String owner_name) -> Array[(Entry::InstanceVariable | Entry::ClassVariable)]
661
604
  def instance_variable_completion_candidates(name, owner_name)
662
- entries = T.cast(prefix_search(name).flatten, T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
605
+ entries = prefix_search(name).flatten #: as Array[Entry::InstanceVariable | Entry::ClassVariable]
663
606
  # Avoid wasting time linearizing ancestors if we didn't find anything
664
607
  return entries if entries.empty?
665
608
 
@@ -674,7 +617,8 @@ module RubyIndexer
674
617
  name_parts = owner_name.split("::")
675
618
 
676
619
  if name_parts.last&.start_with?("<Class:")
677
- attached_name = T.must(name_parts[0..-2]).join("::")
620
+ attached_name = name_parts[0..-2] #: as !nil
621
+ .join("::")
678
622
  attached_ancestors = linearized_ancestors_of(attached_name)
679
623
  variables.concat(class_variables.select { |e| attached_ancestors.any?(e.owner&.name) })
680
624
  else
@@ -686,9 +630,9 @@ module RubyIndexer
686
630
  variables
687
631
  end
688
632
 
689
- sig { params(name: String, owner_name: String).returns(T::Array[Entry::ClassVariable]) }
633
+ #: (String name, String owner_name) -> Array[Entry::ClassVariable]
690
634
  def class_variable_completion_candidates(name, owner_name)
691
- entries = T.cast(prefix_search(name).flatten, T::Array[Entry::ClassVariable])
635
+ entries = prefix_search(name).flatten #: as Array[Entry::ClassVariable]
692
636
  # Avoid wasting time linearizing ancestors if we didn't find anything
693
637
  return entries if entries.empty?
694
638
 
@@ -702,9 +646,7 @@ module RubyIndexer
702
646
  # declarations removed and that the ancestor linearization cache is cleared if necessary. If a block is passed, the
703
647
  # consumer of this API has to handle deleting and inserting/updating entries in the index instead of passing the
704
648
  # document's source (used to handle unsaved changes to files)
705
- sig do
706
- params(uri: URI::Generic, source: T.nilable(String), block: T.nilable(T.proc.params(index: Index).void)).void
707
- end
649
+ #: (URI::Generic uri, ?String? source) ?{ (Index index) -> void } -> void
708
650
  def handle_change(uri, source = nil, &block)
709
651
  key = uri.to_s
710
652
  original_entries = @uris_to_entries[key]
@@ -713,7 +655,10 @@ module RubyIndexer
713
655
  block.call(self)
714
656
  else
715
657
  delete(uri)
716
- index_single(uri, T.must(source))
658
+ index_single(
659
+ uri,
660
+ source, #: as !nil
661
+ )
717
662
  end
718
663
 
719
664
  updated_entries = @uris_to_entries[key]
@@ -723,49 +668,53 @@ module RubyIndexer
723
668
  # indirect means like including a module that than includes the ancestor. Trying to figure out exactly which
724
669
  # ancestors need to be deleted is too expensive. Therefore, if any of the namespace entries has a change to their
725
670
  # ancestor hash, we clear all ancestors and start linearizing lazily again from scratch
726
- original_map = T.cast(
727
- original_entries.select { |e| e.is_a?(Entry::Namespace) },
728
- T::Array[Entry::Namespace],
729
- ).to_h { |e| [e.name, e.ancestor_hash] }
671
+ original_map = original_entries
672
+ .select { |e| e.is_a?(Entry::Namespace) } #: as Array[Entry::Namespace]
673
+ .to_h { |e| [e.name, e.ancestor_hash] }
730
674
 
731
- updated_map = T.cast(
732
- updated_entries.select { |e| e.is_a?(Entry::Namespace) },
733
- T::Array[Entry::Namespace],
734
- ).to_h { |e| [e.name, e.ancestor_hash] }
675
+ updated_map = updated_entries
676
+ .select { |e| e.is_a?(Entry::Namespace) } #: as Array[Entry::Namespace]
677
+ .to_h { |e| [e.name, e.ancestor_hash] }
735
678
 
736
679
  @ancestors.clear if original_map.any? { |name, hash| updated_map[name] != hash }
737
680
  end
738
681
 
739
- sig { returns(T::Boolean) }
682
+ #: -> void
683
+ def clear_ancestors
684
+ @ancestors.clear
685
+ end
686
+
687
+ #: -> bool
740
688
  def empty?
741
689
  @entries.empty?
742
690
  end
743
691
 
744
- sig { returns(T::Array[String]) }
692
+ #: -> Array[String]
745
693
  def names
746
694
  @entries.keys
747
695
  end
748
696
 
749
- sig { params(name: String).returns(T::Boolean) }
697
+ #: (String name) -> bool
750
698
  def indexed?(name)
751
699
  @entries.key?(name)
752
700
  end
753
701
 
754
- sig { returns(Integer) }
702
+ #: -> Integer
755
703
  def length
756
704
  @entries.count
757
705
  end
758
706
 
759
- sig { params(name: String).returns(Entry::SingletonClass) }
707
+ #: (String name) -> Entry::SingletonClass
760
708
  def existing_or_new_singleton_class(name)
761
709
  *_namespace, unqualified_name = name.split("::")
762
710
  full_singleton_name = "#{name}::<Class:#{unqualified_name}>"
763
- singleton = T.cast(self[full_singleton_name]&.first, T.nilable(Entry::SingletonClass))
711
+ singleton = self[full_singleton_name]&.first #: as Entry::SingletonClass?
764
712
 
765
713
  unless singleton
766
- attached_ancestor = T.must(self[name]&.first)
714
+ attached_ancestor = self[name]&.first #: as !nil
767
715
 
768
716
  singleton = Entry::SingletonClass.new(
717
+ @configuration,
769
718
  [full_singleton_name],
770
719
  attached_ancestor.uri,
771
720
  attached_ancestor.location,
@@ -779,12 +728,7 @@ module RubyIndexer
779
728
  singleton
780
729
  end
781
730
 
782
- sig do
783
- type_parameters(:T).params(
784
- uri: String,
785
- type: T.nilable(T::Class[T.all(T.type_parameter(:T), Entry)]),
786
- ).returns(T.nilable(T.any(T::Array[Entry], T::Array[T.type_parameter(:T)])))
787
- end
731
+ #: [T] (String uri, ?Class[(T & Entry)]? type) -> (Array[Entry] | Array[T])?
788
732
  def entries_for(uri, type = nil)
789
733
  entries = @uris_to_entries[uri.to_s]
790
734
  return entries unless type
@@ -796,12 +740,13 @@ module RubyIndexer
796
740
 
797
741
  # Always returns the linearized ancestors for the attached class, regardless of whether `name` refers to a singleton
798
742
  # or attached namespace
799
- sig { params(name: String).returns(T::Array[String]) }
743
+ #: (String name) -> Array[String]
800
744
  def linearized_attached_ancestors(name)
801
745
  name_parts = name.split("::")
802
746
 
803
747
  if name_parts.last&.start_with?("<Class:")
804
- attached_name = T.must(name_parts[0..-2]).join("::")
748
+ attached_name = name_parts[0..-2] #: as !nil
749
+ .join("::")
805
750
  linearized_ancestors_of(attached_name)
806
751
  else
807
752
  linearized_ancestors_of(name)
@@ -809,7 +754,7 @@ module RubyIndexer
809
754
  end
810
755
 
811
756
  # Runs the registered included hooks
812
- sig { params(fully_qualified_name: String, nesting: T::Array[String]).void }
757
+ #: (String fully_qualified_name, Array[String] nesting) -> void
813
758
  def run_included_hooks(fully_qualified_name, nesting)
814
759
  return if @included_hooks.empty?
815
760
 
@@ -824,7 +769,8 @@ module RubyIndexer
824
769
  resolved_modules = resolve(operation.module_name, nesting)
825
770
  next unless resolved_modules
826
771
 
827
- module_name = T.must(resolved_modules.first).name
772
+ module_name = resolved_modules.first #: as !nil
773
+ .name
828
774
 
829
775
  # Then we grab any hooks registered for that module
830
776
  hooks = @included_hooks[module_name]
@@ -838,13 +784,7 @@ module RubyIndexer
838
784
 
839
785
  # Linearize mixins for an array of namespace entries. This method will mutate the `ancestors` array with the
840
786
  # linearized ancestors of the mixins
841
- sig do
842
- params(
843
- ancestors: T::Array[String],
844
- namespace_entries: T::Array[Entry::Namespace],
845
- nesting: T::Array[String],
846
- ).void
847
- end
787
+ #: (Array[String] ancestors, Array[Entry::Namespace] namespace_entries, Array[String] nesting) -> void
848
788
  def linearize_mixins(ancestors, namespace_entries, nesting)
849
789
  mixin_operations = namespace_entries.flat_map(&:mixin_operations)
850
790
  main_namespace_index = 0
@@ -853,7 +793,8 @@ module RubyIndexer
853
793
  resolved_module = resolve(operation.module_name, nesting)
854
794
  next unless resolved_module
855
795
 
856
- module_fully_qualified_name = T.must(resolved_module.first).name
796
+ module_fully_qualified_name = resolved_module.first #: as !nil
797
+ .name
857
798
 
858
799
  case operation
859
800
  when Entry::Prepend
@@ -865,36 +806,27 @@ module RubyIndexer
865
806
  # When there are duplicate prepended modules, we have to insert the new prepends after the existing ones. For
866
807
  # example, if the current ancestors are `["A", "Foo"]` and we try to prepend `["A", "B"]`, then `"B"` has to
867
808
  # be inserted after `"A`
868
- uniq_prepends = linearized_prepends - T.must(ancestors[0...main_namespace_index])
809
+ prepended_ancestors = ancestors[0...main_namespace_index] #: as !nil
810
+ uniq_prepends = linearized_prepends - prepended_ancestors
869
811
  insert_position = linearized_prepends.length - uniq_prepends.length
870
812
 
871
- T.unsafe(ancestors).insert(
872
- insert_position,
873
- *(linearized_prepends - T.must(ancestors[0...main_namespace_index])),
874
- )
813
+ ancestors #: as untyped
814
+ .insert(insert_position, *uniq_prepends)
875
815
 
876
816
  main_namespace_index += linearized_prepends.length
877
817
  when Entry::Include
878
818
  # When including a module, Ruby will always prevent duplicate entries in case the module has already been
879
819
  # prepended or included
880
820
  linearized_includes = linearized_ancestors_of(module_fully_qualified_name)
881
- T.unsafe(ancestors).insert(main_namespace_index + 1, *(linearized_includes - ancestors))
821
+ ancestors #: as untyped
822
+ .insert(main_namespace_index + 1, *(linearized_includes - ancestors))
882
823
  end
883
824
  end
884
825
  end
885
826
 
886
827
  # Linearize the superclass of a given namespace (including modules with the implicit `Module` superclass). This
887
828
  # method will mutate the `ancestors` array with the linearized ancestors of the superclass
888
- sig do
889
- params(
890
- ancestors: T::Array[String],
891
- attached_class_name: String,
892
- fully_qualified_name: String,
893
- namespace_entries: T::Array[Entry::Namespace],
894
- nesting: T::Array[String],
895
- singleton_levels: Integer,
896
- ).void
897
- end
829
+ #: (Array[String] ancestors, String attached_class_name, String fully_qualified_name, Array[Entry::Namespace] namespace_entries, Array[String] nesting, Integer singleton_levels) -> void
898
830
  def linearize_superclass( # rubocop:disable Metrics/ParameterLists
899
831
  ancestors,
900
832
  attached_class_name,
@@ -905,19 +837,27 @@ module RubyIndexer
905
837
  )
906
838
  # Find the first class entry that has a parent class. Notice that if the developer makes a mistake and inherits
907
839
  # from two different classes in different files, we simply ignore it
908
- superclass = T.cast(
909
- if singleton_levels > 0
910
- self[attached_class_name]&.find { |n| n.is_a?(Entry::Class) && n.parent_class }
911
- else
912
- namespace_entries.find { |n| n.is_a?(Entry::Class) && n.parent_class }
913
- end,
914
- T.nilable(Entry::Class),
915
- )
840
+ possible_parents = singleton_levels > 0 ? self[attached_class_name] : namespace_entries
841
+ superclass = nil #: Entry::Class?
842
+
843
+ possible_parents&.each do |n|
844
+ # Ignore non class entries
845
+ next unless n.is_a?(Entry::Class)
846
+
847
+ parent_class = n.parent_class
848
+ next unless parent_class
849
+
850
+ # Always set the superclass, but break early if we found one that isn't `::Object` (meaning we found an explicit
851
+ # parent class and not the implicit default). Note that when setting different parents to the same class, which
852
+ # is invalid, we pick whatever is the first one we find
853
+ superclass = n
854
+ break if parent_class != "::Object"
855
+ end
916
856
 
917
857
  if superclass
918
858
  # If the user makes a mistake and creates a class that inherits from itself, this method would throw a stack
919
859
  # error. We need to ensure that this isn't the case
920
- parent_class = T.must(superclass.parent_class)
860
+ parent_class = superclass.parent_class #: as !nil
921
861
 
922
862
  resolved_parent_class = resolve(parent_class, nesting)
923
863
  parent_class_name = resolved_parent_class&.first&.name
@@ -946,7 +886,7 @@ module RubyIndexer
946
886
  elsif singleton_levels > 0
947
887
  # When computing the linearization for a module's singleton class, it inherits from the linearized ancestors of
948
888
  # the `Module` class
949
- mod = T.cast(self[attached_class_name]&.find { |n| n.is_a?(Entry::Module) }, T.nilable(Entry::Module))
889
+ mod = self[attached_class_name]&.find { |n| n.is_a?(Entry::Module) } #: as Entry::Module?
950
890
 
951
891
  if mod
952
892
  module_class_name_parts = ["Module"]
@@ -962,12 +902,7 @@ module RubyIndexer
962
902
 
963
903
  # Attempts to resolve an UnresolvedAlias into a resolved Alias. If the unresolved alias is pointing to a constant
964
904
  # that doesn't exist, then we return the same UnresolvedAlias
965
- sig do
966
- params(
967
- entry: Entry::UnresolvedConstantAlias,
968
- seen_names: T::Array[String],
969
- ).returns(T.any(Entry::ConstantAlias, Entry::UnresolvedConstantAlias))
970
- end
905
+ #: (Entry::UnresolvedConstantAlias entry, Array[String] seen_names) -> (Entry::ConstantAlias | Entry::UnresolvedConstantAlias)
971
906
  def resolve_alias(entry, seen_names)
972
907
  alias_name = entry.name
973
908
  return entry if seen_names.include?(alias_name)
@@ -977,11 +912,15 @@ module RubyIndexer
977
912
  target = resolve(entry.target, entry.nesting, seen_names)
978
913
  return entry unless target
979
914
 
980
- target_name = T.must(target.first).name
915
+ # Self referential alias can be unresolved we should bail out from resolving
916
+ return entry if target.first == entry
917
+
918
+ target_name = target.first #: as !nil
919
+ .name
981
920
  resolved_alias = Entry::ConstantAlias.new(target_name, entry)
982
921
 
983
922
  # Replace the UnresolvedAlias by a resolved one so that we don't have to do this again later
984
- original_entries = T.must(@entries[alias_name])
923
+ original_entries = @entries[alias_name] #: as !nil
985
924
  original_entries.delete(entry)
986
925
  original_entries << resolved_alias
987
926
 
@@ -990,20 +929,11 @@ module RubyIndexer
990
929
  resolved_alias
991
930
  end
992
931
 
993
- sig do
994
- params(
995
- name: String,
996
- nesting: T::Array[String],
997
- seen_names: T::Array[String],
998
- ).returns(T.nilable(T::Array[T.any(
999
- Entry::Namespace,
1000
- Entry::ConstantAlias,
1001
- Entry::UnresolvedConstantAlias,
1002
- )]))
1003
- end
932
+ #: (String name, Array[String] nesting, Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
1004
933
  def lookup_enclosing_scopes(name, nesting, seen_names)
1005
934
  nesting.length.downto(1) do |i|
1006
- namespace = T.must(nesting[0...i]).join("::")
935
+ namespace = nesting[0...i] #: as !nil
936
+ .join("::")
1007
937
 
1008
938
  # If we find an entry with `full_name` directly, then we can already return it, even if it contains aliases -
1009
939
  # because the user might be trying to jump to the alias definition.
@@ -1019,17 +949,7 @@ module RubyIndexer
1019
949
  nil
1020
950
  end
1021
951
 
1022
- sig do
1023
- params(
1024
- name: String,
1025
- nesting: T::Array[String],
1026
- seen_names: T::Array[String],
1027
- ).returns(T.nilable(T::Array[T.any(
1028
- Entry::Namespace,
1029
- Entry::ConstantAlias,
1030
- Entry::UnresolvedConstantAlias,
1031
- )]))
1032
- end
952
+ #: (String name, Array[String] nesting, Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
1033
953
  def lookup_ancestor_chain(name, nesting, seen_names)
1034
954
  *nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
1035
955
  return if nesting_parts.empty?
@@ -1037,7 +957,9 @@ module RubyIndexer
1037
957
  namespace_entries = resolve(nesting_parts.join("::"), [], seen_names)
1038
958
  return unless namespace_entries
1039
959
 
1040
- ancestors = nesting_parts.empty? ? [] : linearized_ancestors_of(T.must(namespace_entries.first).name)
960
+ namespace_name = namespace_entries.first #: as !nil
961
+ .name
962
+ ancestors = nesting_parts.empty? ? [] : linearized_ancestors_of(namespace_name)
1041
963
 
1042
964
  ancestors.each do |ancestor_name|
1043
965
  entries = direct_or_aliased_constant("#{ancestor_name}::#{constant_name}", seen_names)
@@ -1049,17 +971,7 @@ module RubyIndexer
1049
971
  nil
1050
972
  end
1051
973
 
1052
- sig do
1053
- params(
1054
- name: T.nilable(String),
1055
- nesting: T::Array[String],
1056
- ).returns(T::Array[T::Array[T.any(
1057
- Entry::Namespace,
1058
- Entry::ConstantAlias,
1059
- Entry::UnresolvedConstantAlias,
1060
- Entry::Constant,
1061
- )]])
1062
- end
974
+ #: (String? name, Array[String] nesting) -> Array[Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias | Entry::Constant)]]
1063
975
  def inherited_constant_completion_candidates(name, nesting)
1064
976
  namespace_entries = if name
1065
977
  *nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
@@ -1071,7 +983,9 @@ module RubyIndexer
1071
983
  end
1072
984
  return [] unless namespace_entries
1073
985
 
1074
- ancestors = linearized_ancestors_of(T.must(namespace_entries.first).name)
986
+ namespace_name = namespace_entries.first #: as !nil
987
+ .name
988
+ ancestors = linearized_ancestors_of(namespace_name)
1075
989
  candidates = ancestors.flat_map do |ancestor_name|
1076
990
  @entries_tree.search("#{ancestor_name}::#{constant_name}")
1077
991
  end
@@ -1079,7 +993,8 @@ module RubyIndexer
1079
993
  # For candidates with the same name, we must only show the first entry in the inheritance chain, since that's the
1080
994
  # one the user will be referring to in completion
1081
995
  completion_items = candidates.each_with_object({}) do |entries, hash|
1082
- *parts, short_name = T.must(entries.first).name.split("::")
996
+ *parts, short_name = entries.first #: as !nil
997
+ .name.split("::")
1083
998
  namespace_name = parts.join("::")
1084
999
  ancestor_index = ancestors.index(namespace_name)
1085
1000
  existing_entry, existing_entry_index = hash[short_name]
@@ -1098,7 +1013,7 @@ module RubyIndexer
1098
1013
  # inside of the ["A", "B"] nesting, then we should not concatenate the nesting with the name or else we'll end up
1099
1014
  # with `A::B::A::B::Foo`. This method will remove any redundant parts from the final name based on the reference and
1100
1015
  # the nesting
1101
- sig { params(name: String, nesting: T::Array[String]).returns(String) }
1016
+ #: (String name, Array[String] nesting) -> String
1102
1017
  def build_non_redundant_full_name(name, nesting)
1103
1018
  # If there's no nesting, then we can just return the name as is
1104
1019
  return name if nesting.empty?
@@ -1115,44 +1030,30 @@ module RubyIndexer
1115
1030
  # Otherwise, push all of the leading parts of the nesting that aren't redundant into the name. For example, if we
1116
1031
  # have a reference to `Foo::Bar` inside the `[Namespace, Foo]` nesting, then only the `Foo` part is redundant, but
1117
1032
  # we still need to include the `Namespace` part
1118
- T.unsafe(name_parts).unshift(*nesting[0...first_redundant_part])
1033
+ name_parts.unshift(*nesting[0...first_redundant_part])
1119
1034
  name_parts.join("::")
1120
1035
  end
1121
1036
 
1122
- sig do
1123
- params(
1124
- full_name: String,
1125
- seen_names: T::Array[String],
1126
- ).returns(
1127
- T.nilable(T::Array[T.any(
1128
- Entry::Namespace,
1129
- Entry::ConstantAlias,
1130
- Entry::UnresolvedConstantAlias,
1131
- )]),
1132
- )
1133
- end
1037
+ # Tries to return direct entry from index then non seen canonicalized alias or nil
1038
+ #: (String full_name, Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
1134
1039
  def direct_or_aliased_constant(full_name, seen_names)
1135
- entries = @entries[full_name] || @entries[follow_aliased_namespace(full_name)]
1136
-
1137
- T.cast(
1138
- entries&.map { |e| e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e },
1139
- T.nilable(T::Array[T.any(
1140
- Entry::Namespace,
1141
- Entry::ConstantAlias,
1142
- Entry::UnresolvedConstantAlias,
1143
- )]),
1144
- )
1040
+ if (entries = @entries[full_name])
1041
+ return entries.map do |e|
1042
+ e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
1043
+ end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
1044
+ end
1045
+
1046
+ aliased = follow_aliased_namespace(full_name, seen_names)
1047
+ return if full_name == aliased || seen_names.include?(aliased)
1048
+
1049
+ @entries[aliased]&.map do |e|
1050
+ e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
1051
+ end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
1145
1052
  end
1146
1053
 
1147
1054
  # Attempt to resolve a given unresolved method alias. This method returns the resolved alias if we managed to
1148
1055
  # identify the target or the same unresolved alias entry if we couldn't
1149
- sig do
1150
- params(
1151
- entry: Entry::UnresolvedMethodAlias,
1152
- receiver_name: String,
1153
- seen_names: T::Array[String],
1154
- ).returns(T.any(Entry::MethodAlias, Entry::UnresolvedMethodAlias))
1155
- end
1056
+ #: (Entry::UnresolvedMethodAlias entry, String receiver_name, Array[String] seen_names) -> (Entry::MethodAlias | Entry::UnresolvedMethodAlias)
1156
1057
  def resolve_method_alias(entry, receiver_name, seen_names)
1157
1058
  new_name = entry.new_name
1158
1059
  return entry if new_name == entry.old_name
@@ -1163,8 +1064,11 @@ module RubyIndexer
1163
1064
  target_method_entries = resolve_method(entry.old_name, receiver_name, seen_names)
1164
1065
  return entry unless target_method_entries
1165
1066
 
1166
- resolved_alias = Entry::MethodAlias.new(T.must(target_method_entries.first), entry)
1167
- original_entries = T.must(@entries[new_name])
1067
+ resolved_alias = Entry::MethodAlias.new(
1068
+ target_method_entries.first, #: as !nil
1069
+ entry,
1070
+ )
1071
+ original_entries = @entries[new_name] #: as !nil
1168
1072
  original_entries.delete(entry)
1169
1073
  original_entries << resolved_alias
1170
1074
  resolved_alias