ruby-lsp 0.23.10 → 0.23.13
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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp-launcher +12 -11
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -1
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +81 -115
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +117 -166
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +89 -201
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +63 -192
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +14 -16
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +22 -45
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +42 -60
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +9 -16
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +75 -0
- data/lib/ruby_indexer/test/configuration_test.rb +42 -3
- data/lib/ruby_indexer/test/index_test.rb +21 -0
- data/lib/ruby_indexer/test/method_test.rb +28 -2
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_lsp/addon.rb +44 -71
- data/lib/ruby_lsp/base_server.rb +31 -33
- data/lib/ruby_lsp/client_capabilities.rb +10 -12
- data/lib/ruby_lsp/document.rb +34 -45
- data/lib/ruby_lsp/erb_document.rb +24 -36
- data/lib/ruby_lsp/global_state.rb +51 -56
- data/lib/ruby_lsp/internal.rb +6 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +81 -88
- data/lib/ruby_lsp/listeners/completion.rb +36 -55
- data/lib/ruby_lsp/listeners/definition.rb +37 -51
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +43 -62
- data/lib/ruby_lsp/listeners/document_symbol.rb +35 -49
- data/lib/ruby_lsp/listeners/folding_ranges.rb +32 -39
- data/lib/ruby_lsp/listeners/hover.rb +81 -100
- data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +42 -51
- data/lib/ruby_lsp/listeners/signature_help.rb +6 -25
- data/lib/ruby_lsp/listeners/spec_style.rb +155 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +89 -0
- data/lib/ruby_lsp/listeners/test_style.rb +236 -0
- data/lib/ruby_lsp/node_context.rb +12 -39
- data/lib/ruby_lsp/rbs_document.rb +8 -6
- data/lib/ruby_lsp/requests/code_action_resolve.rb +10 -10
- data/lib/ruby_lsp/requests/code_actions.rb +14 -26
- data/lib/ruby_lsp/requests/code_lens.rb +6 -17
- data/lib/ruby_lsp/requests/completion.rb +7 -20
- data/lib/ruby_lsp/requests/completion_resolve.rb +5 -5
- data/lib/ruby_lsp/requests/definition.rb +8 -17
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/discover_tests.rb +75 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -15
- data/lib/ruby_lsp/requests/document_link.rb +6 -17
- data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
- data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
- data/lib/ruby_lsp/requests/formatting.rb +6 -9
- data/lib/ruby_lsp/requests/go_to_relevant_file.rb +87 -0
- data/lib/ruby_lsp/requests/hover.rb +8 -18
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
- data/lib/ruby_lsp/requests/on_type_formatting.rb +28 -38
- data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +4 -13
- data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
- data/lib/ruby_lsp/requests/references.rb +6 -36
- data/lib/ruby_lsp/requests/rename.rb +11 -37
- data/lib/ruby_lsp/requests/request.rb +7 -19
- data/lib/ruby_lsp/requests/selection_ranges.rb +5 -5
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +12 -31
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -6
- data/lib/ruby_lsp/requests/signature_help.rb +8 -26
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +13 -48
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +9 -12
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +22 -34
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
- data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
- data/lib/ruby_lsp/requests/support/source_uri.rb +16 -30
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
- data/lib/ruby_lsp/requests/support/test_item.rb +55 -0
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +5 -5
- data/lib/ruby_lsp/response_builders/document_symbol.rb +10 -16
- data/lib/ruby_lsp/response_builders/hover.rb +10 -13
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +59 -87
- data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
- data/lib/ruby_lsp/response_builders/test_collection.rb +34 -0
- data/lib/ruby_lsp/ruby_document.rb +22 -60
- data/lib/ruby_lsp/ruby_lsp_reporter_plugin.rb +109 -0
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/server.rb +177 -72
- data/lib/ruby_lsp/setup_bundler.rb +61 -59
- data/lib/ruby_lsp/static_docs.rb +4 -7
- data/lib/ruby_lsp/store.rb +21 -40
- data/lib/ruby_lsp/test_helper.rb +3 -12
- data/lib/ruby_lsp/test_reporter.rb +207 -0
- data/lib/ruby_lsp/test_unit_test_runner.rb +98 -0
- data/lib/ruby_lsp/type_inferrer.rb +9 -13
- data/lib/ruby_lsp/utils.rb +37 -81
- metadata +13 -3
@@ -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,18 +10,19 @@ 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
|
-
|
13
|
+
#: Configuration
|
16
14
|
attr_reader :configuration
|
17
15
|
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
+
#: (Array[String] stack, String? name) -> Array[String]
|
25
24
|
def actual_nesting(stack, name)
|
26
|
-
nesting = stack + [name]
|
25
|
+
nesting = name ? stack + [name] : stack
|
27
26
|
corrected_nesting = []
|
28
27
|
|
29
28
|
nesting.reverse_each do |name|
|
@@ -37,34 +36,31 @@ 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
|
-
|
41
|
-
params(
|
42
|
-
node: T.any(
|
43
|
-
Prism::ConstantPathNode,
|
44
|
-
Prism::ConstantReadNode,
|
45
|
-
Prism::ConstantPathTargetNode,
|
46
|
-
),
|
47
|
-
).returns(T.nilable(String))
|
48
|
-
end
|
39
|
+
#: ((Prism::ConstantPathNode | Prism::ConstantReadNode | Prism::ConstantPathTargetNode | Prism::CallNode | Prism::MissingNode) node) -> String?
|
49
40
|
def constant_name(node)
|
50
|
-
node
|
41
|
+
case node
|
42
|
+
when Prism::CallNode, Prism::MissingNode
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
node.full_name
|
46
|
+
end
|
51
47
|
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
52
48
|
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
53
49
|
nil
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
|
-
|
53
|
+
#: -> void
|
58
54
|
def initialize
|
59
55
|
# Holds all entries in the index using the following format:
|
60
56
|
# {
|
61
57
|
# "Foo" => [#<Entry::Class>, #<Entry::Class>],
|
62
58
|
# "Foo::Bar" => [#<Entry::Class>],
|
63
59
|
# }
|
64
|
-
@entries =
|
60
|
+
@entries = {} #: Hash[String, Array[Entry]]
|
65
61
|
|
66
62
|
# Holds all entries in the index using a prefix tree for searching based on prefixes to provide autocompletion
|
67
|
-
@entries_tree =
|
63
|
+
@entries_tree = PrefixTree[T::Array[Entry]].new #: PrefixTree[Array[Entry]]
|
68
64
|
|
69
65
|
# Holds references to where entries where discovered so that we can easily delete them
|
70
66
|
# {
|
@@ -72,32 +68,29 @@ module RubyIndexer
|
|
72
68
|
# "file:///my/project/bar.rb" => [#<Entry::Class>],
|
73
69
|
# "untitled:Untitled-1" => [#<Entry::Class>],
|
74
70
|
# }
|
75
|
-
@uris_to_entries =
|
71
|
+
@uris_to_entries = {} #: Hash[String, Array[Entry]]
|
76
72
|
|
77
73
|
# Holds all require paths for every indexed item so that we can provide autocomplete for requires
|
78
|
-
@require_paths_tree =
|
74
|
+
@require_paths_tree = PrefixTree[URI::Generic].new #: PrefixTree[URI::Generic]
|
79
75
|
|
80
76
|
# Holds the linearized ancestors list for every namespace
|
81
|
-
@ancestors =
|
77
|
+
@ancestors = {} #: Hash[String, Array[String]]
|
82
78
|
|
83
79
|
# Map of module name to included hooks that have to be executed when we include the given module
|
84
|
-
@included_hooks =
|
85
|
-
{},
|
86
|
-
T::Hash[String, T::Array[T.proc.params(index: Index, base: Entry::Namespace).void]],
|
87
|
-
)
|
80
|
+
@included_hooks = {} #: Hash[String, Array[^(Index index, Entry::Namespace base) -> void]]
|
88
81
|
|
89
|
-
@configuration =
|
82
|
+
@configuration = RubyIndexer::Configuration.new #: Configuration
|
90
83
|
|
91
|
-
@initial_indexing_completed =
|
84
|
+
@initial_indexing_completed = false #: bool
|
92
85
|
end
|
93
86
|
|
94
87
|
# Register an included `hook` that will be executed when `module_name` is included into any namespace
|
95
|
-
|
88
|
+
#: (String module_name) { (Index index, Entry::Namespace base) -> void } -> void
|
96
89
|
def register_included_hook(module_name, &hook)
|
97
90
|
(@included_hooks[module_name] ||= []) << hook
|
98
91
|
end
|
99
92
|
|
100
|
-
|
93
|
+
#: (URI::Generic uri, ?skip_require_paths_tree: bool) -> void
|
101
94
|
def delete(uri, skip_require_paths_tree: false)
|
102
95
|
key = uri.to_s
|
103
96
|
# For each constant discovered in `path`, delete the associated entry from the index. If there are no entries
|
@@ -127,7 +120,7 @@ module RubyIndexer
|
|
127
120
|
@require_paths_tree.delete(require_path) if require_path
|
128
121
|
end
|
129
122
|
|
130
|
-
|
123
|
+
#: (Entry entry, ?skip_prefix_tree: bool) -> void
|
131
124
|
def add(entry, skip_prefix_tree: false)
|
132
125
|
name = entry.name
|
133
126
|
|
@@ -136,28 +129,19 @@ module RubyIndexer
|
|
136
129
|
@entries_tree.insert(name, T.must(@entries[name])) unless skip_prefix_tree
|
137
130
|
end
|
138
131
|
|
139
|
-
|
132
|
+
#: (String fully_qualified_name) -> Array[Entry]?
|
140
133
|
def [](fully_qualified_name)
|
141
134
|
@entries[fully_qualified_name.delete_prefix("::")]
|
142
135
|
end
|
143
136
|
|
144
|
-
|
137
|
+
#: (String query) -> Array[URI::Generic]
|
145
138
|
def search_require_paths(query)
|
146
139
|
@require_paths_tree.search(query)
|
147
140
|
end
|
148
141
|
|
149
142
|
# Searches for a constant based on an unqualified name and returns the first possible match regardless of whether
|
150
143
|
# there are more possible matching entries
|
151
|
-
|
152
|
-
params(
|
153
|
-
name: String,
|
154
|
-
).returns(T.nilable(T::Array[T.any(
|
155
|
-
Entry::Namespace,
|
156
|
-
Entry::ConstantAlias,
|
157
|
-
Entry::UnresolvedConstantAlias,
|
158
|
-
Entry::Constant,
|
159
|
-
)]))
|
160
|
-
end
|
144
|
+
#: (String name) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias | Entry::Constant)]?
|
161
145
|
def first_unqualified_const(name)
|
162
146
|
# Look for an exact match first
|
163
147
|
_name, entries = @entries.find do |const_name, _entries|
|
@@ -195,7 +179,7 @@ module RubyIndexer
|
|
195
179
|
# [#<Entry::Class name="Foo::Baz">],
|
196
180
|
# ]
|
197
181
|
# ```
|
198
|
-
|
182
|
+
#: (String query, ?Array[String]? nesting) -> Array[Array[Entry]]
|
199
183
|
def prefix_search(query, nesting = nil)
|
200
184
|
unless nesting
|
201
185
|
results = @entries_tree.search(query)
|
@@ -214,7 +198,7 @@ module RubyIndexer
|
|
214
198
|
end
|
215
199
|
|
216
200
|
# Fuzzy searches index entries based on Jaro-Winkler similarity. If no query is provided, all entries are returned
|
217
|
-
|
201
|
+
#: (String? query) -> Array[Entry]
|
218
202
|
def fuzzy_search(query)
|
219
203
|
unless query
|
220
204
|
entries = @entries.filter_map do |_name, entries|
|
@@ -238,12 +222,7 @@ module RubyIndexer
|
|
238
222
|
results.flat_map(&:first)
|
239
223
|
end
|
240
224
|
|
241
|
-
|
242
|
-
params(
|
243
|
-
name: T.nilable(String),
|
244
|
-
receiver_name: String,
|
245
|
-
).returns(T::Array[T.any(Entry::Member, Entry::MethodAlias)])
|
246
|
-
end
|
225
|
+
#: (String? name, String receiver_name) -> Array[(Entry::Member | Entry::MethodAlias)]
|
247
226
|
def method_completion_candidates(name, receiver_name)
|
248
227
|
ancestors = linearized_ancestors_of(receiver_name)
|
249
228
|
|
@@ -286,17 +265,7 @@ module RubyIndexer
|
|
286
265
|
completion_items.values.map!(&:first)
|
287
266
|
end
|
288
267
|
|
289
|
-
|
290
|
-
params(
|
291
|
-
name: String,
|
292
|
-
nesting: T::Array[String],
|
293
|
-
).returns(T::Array[T::Array[T.any(
|
294
|
-
Entry::Constant,
|
295
|
-
Entry::ConstantAlias,
|
296
|
-
Entry::Namespace,
|
297
|
-
Entry::UnresolvedConstantAlias,
|
298
|
-
)]])
|
299
|
-
end
|
268
|
+
#: (String name, Array[String] nesting) -> Array[Array[(Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias)]]
|
300
269
|
def constant_completion_candidates(name, nesting)
|
301
270
|
# If we have a top level reference, then we don't need to include completions inside the current nesting
|
302
271
|
if name.start_with?("::")
|
@@ -351,17 +320,7 @@ module RubyIndexer
|
|
351
320
|
# nesting: the nesting structure where the reference was found (e.g.: ["Foo", "Bar"])
|
352
321
|
# seen_names: this parameter should not be used by consumers of the api. It is used to avoid infinite recursion when
|
353
322
|
# resolving circular references
|
354
|
-
|
355
|
-
params(
|
356
|
-
name: String,
|
357
|
-
nesting: T::Array[String],
|
358
|
-
seen_names: T::Array[String],
|
359
|
-
).returns(T.nilable(T::Array[T.any(
|
360
|
-
Entry::Namespace,
|
361
|
-
Entry::ConstantAlias,
|
362
|
-
Entry::UnresolvedConstantAlias,
|
363
|
-
)]))
|
364
|
-
end
|
323
|
+
#: (String name, Array[String] nesting, ?Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
365
324
|
def resolve(name, nesting, seen_names = [])
|
366
325
|
# If we have a top level reference, then we just search for it straight away ignoring the nesting
|
367
326
|
if name.start_with?("::")
|
@@ -397,12 +356,7 @@ module RubyIndexer
|
|
397
356
|
# Index all files for the given URIs, which defaults to what is configured. A block can be used to track and control
|
398
357
|
# indexing progress. That block is invoked with the current progress percentage and should return `true` to continue
|
399
358
|
# indexing or `false` to stop indexing.
|
400
|
-
|
401
|
-
params(
|
402
|
-
uris: T::Array[URI::Generic],
|
403
|
-
block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
|
404
|
-
).void
|
405
|
-
end
|
359
|
+
#: (?uris: Array[URI::Generic]) ?{ (Integer progress) -> bool } -> void
|
406
360
|
def index_all(uris: @configuration.indexable_uris, &block)
|
407
361
|
# When troubleshooting an indexing issue, e.g. through irb, it's not obvious that `index_all` will augment the
|
408
362
|
# existing index values, meaning it may contain 'stale' entries. This check ensures that the user is aware of this
|
@@ -412,8 +366,6 @@ module RubyIndexer
|
|
412
366
|
"The index is not empty. To prevent invalid entries, `index_all` can only be called once."
|
413
367
|
end
|
414
368
|
|
415
|
-
@initial_indexing_completed = true
|
416
|
-
|
417
369
|
RBSIndexer.new(self).index_ruby_core
|
418
370
|
# Calculate how many paths are worth 1% of progress
|
419
371
|
progress_step = (uris.length / 100.0).ceil
|
@@ -426,9 +378,11 @@ module RubyIndexer
|
|
426
378
|
|
427
379
|
index_file(uri, collect_comments: false)
|
428
380
|
end
|
381
|
+
|
382
|
+
@initial_indexing_completed = true
|
429
383
|
end
|
430
384
|
|
431
|
-
|
385
|
+
#: (URI::Generic uri, String source, ?collect_comments: bool) -> void
|
432
386
|
def index_single(uri, source, collect_comments: true)
|
433
387
|
dispatcher = Prism::Dispatcher.new
|
434
388
|
|
@@ -450,7 +404,7 @@ module RubyIndexer
|
|
450
404
|
end
|
451
405
|
|
452
406
|
# Indexes a File URI by reading the contents from disk
|
453
|
-
|
407
|
+
#: (URI::Generic uri, ?collect_comments: bool) -> void
|
454
408
|
def index_file(uri, collect_comments: true)
|
455
409
|
index_single(uri, File.read(T.must(uri.full_path)), collect_comments: collect_comments)
|
456
410
|
rescue Errno::EISDIR, Errno::ENOENT
|
@@ -468,7 +422,7 @@ module RubyIndexer
|
|
468
422
|
# If we find an alias, then we want to follow its target. In the same example, if `Foo::Bar` is an alias to
|
469
423
|
# `Something::Else`, then we first discover `Something::Else::Baz`. But `Something::Else::Baz` might contain other
|
470
424
|
# aliases, so we have to invoke `follow_aliased_namespace` again to check until we only return a real name
|
471
|
-
|
425
|
+
#: (String name, ?Array[String] seen_names) -> String
|
472
426
|
def follow_aliased_namespace(name, seen_names = [])
|
473
427
|
parts = name.split("::")
|
474
428
|
real_parts = []
|
@@ -501,14 +455,7 @@ module RubyIndexer
|
|
501
455
|
# Attempts to find methods for a resolved fully qualified receiver name. Do not provide the `seen_names` parameter
|
502
456
|
# as it is used only internally to prevent infinite loops when resolving circular aliases
|
503
457
|
# Returns `nil` if the method does not exist on that receiver
|
504
|
-
|
505
|
-
params(
|
506
|
-
method_name: String,
|
507
|
-
receiver_name: String,
|
508
|
-
seen_names: T::Array[String],
|
509
|
-
inherited_only: T::Boolean,
|
510
|
-
).returns(T.nilable(T::Array[T.any(Entry::Member, Entry::MethodAlias)]))
|
511
|
-
end
|
458
|
+
#: (String method_name, String receiver_name, ?Array[String] seen_names, ?inherited_only: bool) -> Array[(Entry::Member | Entry::MethodAlias)]?
|
512
459
|
def resolve_method(method_name, receiver_name, seen_names = [], inherited_only: false)
|
513
460
|
method_entries = self[method_name]
|
514
461
|
return unless method_entries
|
@@ -546,7 +493,7 @@ module RubyIndexer
|
|
546
493
|
# module that prepends another module, then the prepend module appears before the included module.
|
547
494
|
#
|
548
495
|
# The order of ancestors is [linearized_prepends, self, linearized_includes, linearized_superclass]
|
549
|
-
|
496
|
+
#: (String fully_qualified_name) -> Array[String]
|
550
497
|
def linearized_ancestors_of(fully_qualified_name)
|
551
498
|
# If we already computed the ancestors for this namespace, return it straight away
|
552
499
|
cached_ancestors = @ancestors[fully_qualified_name]
|
@@ -624,7 +571,7 @@ module RubyIndexer
|
|
624
571
|
|
625
572
|
# Resolves an instance variable name for a given owner name. This method will linearize the ancestors of the owner
|
626
573
|
# and find inherited instance variables as well
|
627
|
-
|
574
|
+
#: (String variable_name, String owner_name) -> Array[Entry::InstanceVariable]?
|
628
575
|
def resolve_instance_variable(variable_name, owner_name)
|
629
576
|
entries = T.cast(self[variable_name], T.nilable(T::Array[Entry::InstanceVariable]))
|
630
577
|
return unless entries
|
@@ -635,7 +582,7 @@ module RubyIndexer
|
|
635
582
|
entries.select { |e| ancestors.include?(e.owner&.name) }
|
636
583
|
end
|
637
584
|
|
638
|
-
|
585
|
+
#: (String variable_name, String owner_name) -> Array[Entry::ClassVariable]?
|
639
586
|
def resolve_class_variable(variable_name, owner_name)
|
640
587
|
entries = self[variable_name]&.grep(Entry::ClassVariable)
|
641
588
|
return unless entries&.any?
|
@@ -648,9 +595,7 @@ module RubyIndexer
|
|
648
595
|
|
649
596
|
# Returns a list of possible candidates for completion of instance variables for a given owner name. The name must
|
650
597
|
# include the `@` prefix
|
651
|
-
|
652
|
-
params(name: String, owner_name: String).returns(T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
|
653
|
-
end
|
598
|
+
#: (String name, String owner_name) -> Array[(Entry::InstanceVariable | Entry::ClassVariable)]
|
654
599
|
def instance_variable_completion_candidates(name, owner_name)
|
655
600
|
entries = T.cast(prefix_search(name).flatten, T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
|
656
601
|
# Avoid wasting time linearizing ancestors if we didn't find anything
|
@@ -679,7 +624,7 @@ module RubyIndexer
|
|
679
624
|
variables
|
680
625
|
end
|
681
626
|
|
682
|
-
|
627
|
+
#: (String name, String owner_name) -> Array[Entry::ClassVariable]
|
683
628
|
def class_variable_completion_candidates(name, owner_name)
|
684
629
|
entries = T.cast(prefix_search(name).flatten, T::Array[Entry::ClassVariable])
|
685
630
|
# Avoid wasting time linearizing ancestors if we didn't find anything
|
@@ -695,9 +640,7 @@ module RubyIndexer
|
|
695
640
|
# declarations removed and that the ancestor linearization cache is cleared if necessary. If a block is passed, the
|
696
641
|
# consumer of this API has to handle deleting and inserting/updating entries in the index instead of passing the
|
697
642
|
# document's source (used to handle unsaved changes to files)
|
698
|
-
|
699
|
-
params(uri: URI::Generic, source: T.nilable(String), block: T.nilable(T.proc.params(index: Index).void)).void
|
700
|
-
end
|
643
|
+
#: (URI::Generic uri, ?String? source) ?{ (Index index) -> void } -> void
|
701
644
|
def handle_change(uri, source = nil, &block)
|
702
645
|
key = uri.to_s
|
703
646
|
original_entries = @uris_to_entries[key]
|
@@ -729,27 +672,27 @@ module RubyIndexer
|
|
729
672
|
@ancestors.clear if original_map.any? { |name, hash| updated_map[name] != hash }
|
730
673
|
end
|
731
674
|
|
732
|
-
|
675
|
+
#: -> bool
|
733
676
|
def empty?
|
734
677
|
@entries.empty?
|
735
678
|
end
|
736
679
|
|
737
|
-
|
680
|
+
#: -> Array[String]
|
738
681
|
def names
|
739
682
|
@entries.keys
|
740
683
|
end
|
741
684
|
|
742
|
-
|
685
|
+
#: (String name) -> bool
|
743
686
|
def indexed?(name)
|
744
687
|
@entries.key?(name)
|
745
688
|
end
|
746
689
|
|
747
|
-
|
690
|
+
#: -> Integer
|
748
691
|
def length
|
749
692
|
@entries.count
|
750
693
|
end
|
751
694
|
|
752
|
-
|
695
|
+
#: (String name) -> Entry::SingletonClass
|
753
696
|
def existing_or_new_singleton_class(name)
|
754
697
|
*_namespace, unqualified_name = name.split("::")
|
755
698
|
full_singleton_name = "#{name}::<Class:#{unqualified_name}>"
|
@@ -772,12 +715,7 @@ module RubyIndexer
|
|
772
715
|
singleton
|
773
716
|
end
|
774
717
|
|
775
|
-
|
776
|
-
type_parameters(:T).params(
|
777
|
-
uri: String,
|
778
|
-
type: T.nilable(T::Class[T.all(T.type_parameter(:T), Entry)]),
|
779
|
-
).returns(T.nilable(T.any(T::Array[Entry], T::Array[T.type_parameter(:T)])))
|
780
|
-
end
|
718
|
+
#: [T] (String uri, ?Class[(T & Entry)]? type) -> (Array[Entry] | Array[T])?
|
781
719
|
def entries_for(uri, type = nil)
|
782
720
|
entries = @uris_to_entries[uri.to_s]
|
783
721
|
return entries unless type
|
@@ -789,7 +727,7 @@ module RubyIndexer
|
|
789
727
|
|
790
728
|
# Always returns the linearized ancestors for the attached class, regardless of whether `name` refers to a singleton
|
791
729
|
# or attached namespace
|
792
|
-
|
730
|
+
#: (String name) -> Array[String]
|
793
731
|
def linearized_attached_ancestors(name)
|
794
732
|
name_parts = name.split("::")
|
795
733
|
|
@@ -802,7 +740,7 @@ module RubyIndexer
|
|
802
740
|
end
|
803
741
|
|
804
742
|
# Runs the registered included hooks
|
805
|
-
|
743
|
+
#: (String fully_qualified_name, Array[String] nesting) -> void
|
806
744
|
def run_included_hooks(fully_qualified_name, nesting)
|
807
745
|
return if @included_hooks.empty?
|
808
746
|
|
@@ -831,13 +769,7 @@ module RubyIndexer
|
|
831
769
|
|
832
770
|
# Linearize mixins for an array of namespace entries. This method will mutate the `ancestors` array with the
|
833
771
|
# linearized ancestors of the mixins
|
834
|
-
|
835
|
-
params(
|
836
|
-
ancestors: T::Array[String],
|
837
|
-
namespace_entries: T::Array[Entry::Namespace],
|
838
|
-
nesting: T::Array[String],
|
839
|
-
).void
|
840
|
-
end
|
772
|
+
#: (Array[String] ancestors, Array[Entry::Namespace] namespace_entries, Array[String] nesting) -> void
|
841
773
|
def linearize_mixins(ancestors, namespace_entries, nesting)
|
842
774
|
mixin_operations = namespace_entries.flat_map(&:mixin_operations)
|
843
775
|
main_namespace_index = 0
|
@@ -878,16 +810,7 @@ module RubyIndexer
|
|
878
810
|
|
879
811
|
# Linearize the superclass of a given namespace (including modules with the implicit `Module` superclass). This
|
880
812
|
# method will mutate the `ancestors` array with the linearized ancestors of the superclass
|
881
|
-
|
882
|
-
params(
|
883
|
-
ancestors: T::Array[String],
|
884
|
-
attached_class_name: String,
|
885
|
-
fully_qualified_name: String,
|
886
|
-
namespace_entries: T::Array[Entry::Namespace],
|
887
|
-
nesting: T::Array[String],
|
888
|
-
singleton_levels: Integer,
|
889
|
-
).void
|
890
|
-
end
|
813
|
+
#: (Array[String] ancestors, String attached_class_name, String fully_qualified_name, Array[Entry::Namespace] namespace_entries, Array[String] nesting, Integer singleton_levels) -> void
|
891
814
|
def linearize_superclass( # rubocop:disable Metrics/ParameterLists
|
892
815
|
ancestors,
|
893
816
|
attached_class_name,
|
@@ -955,12 +878,7 @@ module RubyIndexer
|
|
955
878
|
|
956
879
|
# Attempts to resolve an UnresolvedAlias into a resolved Alias. If the unresolved alias is pointing to a constant
|
957
880
|
# that doesn't exist, then we return the same UnresolvedAlias
|
958
|
-
|
959
|
-
params(
|
960
|
-
entry: Entry::UnresolvedConstantAlias,
|
961
|
-
seen_names: T::Array[String],
|
962
|
-
).returns(T.any(Entry::ConstantAlias, Entry::UnresolvedConstantAlias))
|
963
|
-
end
|
881
|
+
#: (Entry::UnresolvedConstantAlias entry, Array[String] seen_names) -> (Entry::ConstantAlias | Entry::UnresolvedConstantAlias)
|
964
882
|
def resolve_alias(entry, seen_names)
|
965
883
|
alias_name = entry.name
|
966
884
|
return entry if seen_names.include?(alias_name)
|
@@ -983,17 +901,7 @@ module RubyIndexer
|
|
983
901
|
resolved_alias
|
984
902
|
end
|
985
903
|
|
986
|
-
|
987
|
-
params(
|
988
|
-
name: String,
|
989
|
-
nesting: T::Array[String],
|
990
|
-
seen_names: T::Array[String],
|
991
|
-
).returns(T.nilable(T::Array[T.any(
|
992
|
-
Entry::Namespace,
|
993
|
-
Entry::ConstantAlias,
|
994
|
-
Entry::UnresolvedConstantAlias,
|
995
|
-
)]))
|
996
|
-
end
|
904
|
+
#: (String name, Array[String] nesting, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
997
905
|
def lookup_enclosing_scopes(name, nesting, seen_names)
|
998
906
|
nesting.length.downto(1) do |i|
|
999
907
|
namespace = T.must(nesting[0...i]).join("::")
|
@@ -1012,17 +920,7 @@ module RubyIndexer
|
|
1012
920
|
nil
|
1013
921
|
end
|
1014
922
|
|
1015
|
-
|
1016
|
-
params(
|
1017
|
-
name: String,
|
1018
|
-
nesting: T::Array[String],
|
1019
|
-
seen_names: T::Array[String],
|
1020
|
-
).returns(T.nilable(T::Array[T.any(
|
1021
|
-
Entry::Namespace,
|
1022
|
-
Entry::ConstantAlias,
|
1023
|
-
Entry::UnresolvedConstantAlias,
|
1024
|
-
)]))
|
1025
|
-
end
|
923
|
+
#: (String name, Array[String] nesting, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
1026
924
|
def lookup_ancestor_chain(name, nesting, seen_names)
|
1027
925
|
*nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
|
1028
926
|
return if nesting_parts.empty?
|
@@ -1042,17 +940,7 @@ module RubyIndexer
|
|
1042
940
|
nil
|
1043
941
|
end
|
1044
942
|
|
1045
|
-
|
1046
|
-
params(
|
1047
|
-
name: T.nilable(String),
|
1048
|
-
nesting: T::Array[String],
|
1049
|
-
).returns(T::Array[T::Array[T.any(
|
1050
|
-
Entry::Namespace,
|
1051
|
-
Entry::ConstantAlias,
|
1052
|
-
Entry::UnresolvedConstantAlias,
|
1053
|
-
Entry::Constant,
|
1054
|
-
)]])
|
1055
|
-
end
|
943
|
+
#: (String? name, Array[String] nesting) -> Array[Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias | Entry::Constant)]]
|
1056
944
|
def inherited_constant_completion_candidates(name, nesting)
|
1057
945
|
namespace_entries = if name
|
1058
946
|
*nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
|
@@ -1091,7 +979,7 @@ module RubyIndexer
|
|
1091
979
|
# inside of the ["A", "B"] nesting, then we should not concatenate the nesting with the name or else we'll end up
|
1092
980
|
# with `A::B::A::B::Foo`. This method will remove any redundant parts from the final name based on the reference and
|
1093
981
|
# the nesting
|
1094
|
-
|
982
|
+
#: (String name, Array[String] nesting) -> String
|
1095
983
|
def build_non_redundant_full_name(name, nesting)
|
1096
984
|
# If there's no nesting, then we can just return the name as is
|
1097
985
|
return name if nesting.empty?
|
@@ -1112,18 +1000,7 @@ module RubyIndexer
|
|
1112
1000
|
name_parts.join("::")
|
1113
1001
|
end
|
1114
1002
|
|
1115
|
-
|
1116
|
-
params(
|
1117
|
-
full_name: String,
|
1118
|
-
seen_names: T::Array[String],
|
1119
|
-
).returns(
|
1120
|
-
T.nilable(T::Array[T.any(
|
1121
|
-
Entry::Namespace,
|
1122
|
-
Entry::ConstantAlias,
|
1123
|
-
Entry::UnresolvedConstantAlias,
|
1124
|
-
)]),
|
1125
|
-
)
|
1126
|
-
end
|
1003
|
+
#: (String full_name, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
1127
1004
|
def direct_or_aliased_constant(full_name, seen_names)
|
1128
1005
|
entries = @entries[full_name] || @entries[follow_aliased_namespace(full_name)]
|
1129
1006
|
|
@@ -1139,13 +1016,7 @@ module RubyIndexer
|
|
1139
1016
|
|
1140
1017
|
# Attempt to resolve a given unresolved method alias. This method returns the resolved alias if we managed to
|
1141
1018
|
# identify the target or the same unresolved alias entry if we couldn't
|
1142
|
-
|
1143
|
-
params(
|
1144
|
-
entry: Entry::UnresolvedMethodAlias,
|
1145
|
-
receiver_name: String,
|
1146
|
-
seen_names: T::Array[String],
|
1147
|
-
).returns(T.any(Entry::MethodAlias, Entry::UnresolvedMethodAlias))
|
1148
|
-
end
|
1019
|
+
#: (Entry::UnresolvedMethodAlias entry, String receiver_name, Array[String] seen_names) -> (Entry::MethodAlias | Entry::UnresolvedMethodAlias)
|
1149
1020
|
def resolve_method_alias(entry, receiver_name, seen_names)
|
1150
1021
|
new_name = entry.new_name
|
1151
1022
|
return entry if new_name == entry.old_name
|
@@ -3,20 +3,8 @@
|
|
3
3
|
|
4
4
|
module RubyIndexer
|
5
5
|
class Location
|
6
|
-
extend T::Sig
|
7
|
-
|
8
6
|
class << self
|
9
|
-
|
10
|
-
|
11
|
-
sig do
|
12
|
-
params(
|
13
|
-
prism_location: Prism::Location,
|
14
|
-
code_units_cache: T.any(
|
15
|
-
T.proc.params(arg0: Integer).returns(Integer),
|
16
|
-
Prism::CodeUnitsCache,
|
17
|
-
),
|
18
|
-
).returns(T.attached_class)
|
19
|
-
end
|
7
|
+
#: (Prism::Location prism_location, (^(Integer arg0) -> Integer | Prism::CodeUnitsCache) code_units_cache) -> instance
|
20
8
|
def from_prism_location(prism_location, code_units_cache)
|
21
9
|
new(
|
22
10
|
prism_location.start_line,
|
@@ -27,17 +15,10 @@ module RubyIndexer
|
|
27
15
|
end
|
28
16
|
end
|
29
17
|
|
30
|
-
|
18
|
+
#: Integer
|
31
19
|
attr_reader :start_line, :end_line, :start_column, :end_column
|
32
20
|
|
33
|
-
|
34
|
-
params(
|
35
|
-
start_line: Integer,
|
36
|
-
end_line: Integer,
|
37
|
-
start_column: Integer,
|
38
|
-
end_column: Integer,
|
39
|
-
).void
|
40
|
-
end
|
21
|
+
#: (Integer start_line, Integer end_line, Integer start_column, Integer end_column) -> void
|
41
22
|
def initialize(start_line, end_line, start_column, end_column)
|
42
23
|
@start_line = start_line
|
43
24
|
@end_line = end_line
|
@@ -45,11 +26,7 @@ module RubyIndexer
|
|
45
26
|
@end_column = end_column
|
46
27
|
end
|
47
28
|
|
48
|
-
|
49
|
-
params(
|
50
|
-
other: T.any(Location, Prism::Location),
|
51
|
-
).returns(T::Boolean)
|
52
|
-
end
|
29
|
+
#: ((Location | Prism::Location) other) -> bool
|
53
30
|
def ==(other)
|
54
31
|
start_line == other.start_line &&
|
55
32
|
end_line == other.end_line &&
|