ruby-lsp 0.22.1 → 0.23.10
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 +12 -11
- data/exe/ruby-lsp-check +5 -5
- data/exe/ruby-lsp-launcher +41 -15
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +191 -100
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +174 -61
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +12 -0
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +82 -61
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +36 -0
- data/lib/ruby_indexer/ruby_indexer.rb +2 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +30 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +143 -44
- data/lib/ruby_indexer/test/instance_variables_test.rb +20 -0
- data/lib/ruby_indexer/test/method_test.rb +86 -8
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +90 -2
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +17 -18
- data/lib/ruby_lsp/client_capabilities.rb +7 -1
- data/lib/ruby_lsp/document.rb +72 -10
- data/lib/ruby_lsp/erb_document.rb +5 -3
- data/lib/ruby_lsp/global_state.rb +42 -3
- data/lib/ruby_lsp/internal.rb +3 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +9 -5
- data/lib/ruby_lsp/listeners/completion.rb +78 -6
- data/lib/ruby_lsp/listeners/definition.rb +80 -19
- data/lib/ruby_lsp/listeners/document_highlight.rb +3 -2
- data/lib/ruby_lsp/listeners/document_link.rb +21 -3
- data/lib/ruby_lsp/listeners/document_symbol.rb +12 -1
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +59 -2
- data/lib/ruby_lsp/load_sorbet.rb +3 -3
- data/lib/ruby_lsp/rbs_document.rb +2 -2
- data/lib/ruby_lsp/requests/code_action_resolve.rb +90 -6
- data/lib/ruby_lsp/requests/code_actions.rb +57 -1
- data/lib/ruby_lsp/requests/completion.rb +8 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +7 -1
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
- data/lib/ruby_lsp/requests/folding_ranges.rb +2 -6
- data/lib/ruby_lsp/requests/formatting.rb +2 -6
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +2 -2
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/references.rb +29 -2
- data/lib/ruby_lsp/requests/rename.rb +17 -7
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -4
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +2 -9
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +3 -3
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -13
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -3
- data/lib/ruby_lsp/ruby_document.rb +80 -6
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +205 -61
- data/lib/ruby_lsp/setup_bundler.rb +50 -43
- data/lib/ruby_lsp/store.rb +7 -7
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +60 -31
- data/lib/ruby_lsp/utils.rb +63 -3
- metadata +8 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -43,7 +43,7 @@ module RubyIndexer
|
|
43
43
|
handle_class_or_module_declaration(declaration, pathname)
|
44
44
|
when RBS::AST::Declarations::Constant
|
45
45
|
namespace_nesting = declaration.name.namespace.path.map(&:to_s)
|
46
|
-
handle_constant(declaration, namespace_nesting, pathname.to_s)
|
46
|
+
handle_constant(declaration, namespace_nesting, URI::Generic.from_path(path: pathname.to_s))
|
47
47
|
when RBS::AST::Declarations::Global
|
48
48
|
handle_global_variable(declaration, pathname)
|
49
49
|
else # rubocop:disable Style/EmptyElse
|
@@ -56,23 +56,25 @@ module RubyIndexer
|
|
56
56
|
end
|
57
57
|
def handle_class_or_module_declaration(declaration, pathname)
|
58
58
|
nesting = [declaration.name.name.to_s]
|
59
|
-
|
59
|
+
uri = URI::Generic.from_path(path: pathname.to_s)
|
60
60
|
location = to_ruby_indexer_location(declaration.location)
|
61
61
|
comments = comments_to_string(declaration)
|
62
62
|
entry = if declaration.is_a?(RBS::AST::Declarations::Class)
|
63
63
|
parent_class = declaration.super_class&.name&.name&.to_s
|
64
|
-
Entry::Class.new(nesting,
|
64
|
+
Entry::Class.new(nesting, uri, location, location, comments, parent_class)
|
65
65
|
else
|
66
|
-
Entry::Module.new(nesting,
|
66
|
+
Entry::Module.new(nesting, uri, location, location, comments)
|
67
67
|
end
|
68
|
+
|
68
69
|
add_declaration_mixins_to_entry(declaration, entry)
|
69
70
|
@index.add(entry)
|
71
|
+
|
70
72
|
declaration.members.each do |member|
|
71
73
|
case member
|
72
74
|
when RBS::AST::Members::MethodDefinition
|
73
75
|
handle_method(member, entry)
|
74
76
|
when RBS::AST::Declarations::Constant
|
75
|
-
handle_constant(member, nesting,
|
77
|
+
handle_constant(member, nesting, uri)
|
76
78
|
when RBS::AST::Members::Alias
|
77
79
|
# In RBS, an alias means that two methods have the same signature.
|
78
80
|
# It does not mean the same thing as a Ruby alias.
|
@@ -115,7 +117,7 @@ module RubyIndexer
|
|
115
117
|
sig { params(member: RBS::AST::Members::MethodDefinition, owner: Entry::Namespace).void }
|
116
118
|
def handle_method(member, owner)
|
117
119
|
name = member.name.name
|
118
|
-
|
120
|
+
uri = URI::Generic.from_path(path: member.location.buffer.name)
|
119
121
|
location = to_ruby_indexer_location(member.location)
|
120
122
|
comments = comments_to_string(member)
|
121
123
|
|
@@ -132,7 +134,7 @@ module RubyIndexer
|
|
132
134
|
signatures = signatures(member)
|
133
135
|
@index.add(Entry::Method.new(
|
134
136
|
name,
|
135
|
-
|
137
|
+
uri,
|
136
138
|
location,
|
137
139
|
location,
|
138
140
|
comments,
|
@@ -260,12 +262,12 @@ module RubyIndexer
|
|
260
262
|
# Complex::I = ... # Complex::I is a top-level constant
|
261
263
|
#
|
262
264
|
# And we need to handle their nesting differently.
|
263
|
-
sig { params(declaration: RBS::AST::Declarations::Constant, nesting: T::Array[String],
|
264
|
-
def handle_constant(declaration, nesting,
|
265
|
+
sig { params(declaration: RBS::AST::Declarations::Constant, nesting: T::Array[String], uri: URI::Generic).void }
|
266
|
+
def handle_constant(declaration, nesting, uri)
|
265
267
|
fully_qualified_name = [*nesting, declaration.name.name.to_s].join("::")
|
266
268
|
@index.add(Entry::Constant.new(
|
267
269
|
fully_qualified_name,
|
268
|
-
|
270
|
+
uri,
|
269
271
|
to_ruby_indexer_location(declaration.location),
|
270
272
|
comments_to_string(declaration),
|
271
273
|
))
|
@@ -274,13 +276,13 @@ module RubyIndexer
|
|
274
276
|
sig { params(declaration: RBS::AST::Declarations::Global, pathname: Pathname).void }
|
275
277
|
def handle_global_variable(declaration, pathname)
|
276
278
|
name = declaration.name.to_s
|
277
|
-
|
279
|
+
uri = URI::Generic.from_path(path: pathname.to_s)
|
278
280
|
location = to_ruby_indexer_location(declaration.location)
|
279
281
|
comments = comments_to_string(declaration)
|
280
282
|
|
281
283
|
@index.add(Entry::GlobalVariable.new(
|
282
284
|
name,
|
283
|
-
|
285
|
+
uri,
|
284
286
|
location,
|
285
287
|
comments,
|
286
288
|
))
|
@@ -288,14 +290,14 @@ module RubyIndexer
|
|
288
290
|
|
289
291
|
sig { params(member: RBS::AST::Members::Alias, owner_entry: Entry::Namespace).void }
|
290
292
|
def handle_signature_alias(member, owner_entry)
|
291
|
-
|
293
|
+
uri = URI::Generic.from_path(path: member.location.buffer.name)
|
292
294
|
comments = comments_to_string(member)
|
293
295
|
|
294
296
|
entry = Entry::UnresolvedMethodAlias.new(
|
295
297
|
member.new_name.to_s,
|
296
298
|
member.old_name.to_s,
|
297
299
|
owner_entry,
|
298
|
-
|
300
|
+
uri,
|
299
301
|
to_ruby_indexer_location(member.location),
|
300
302
|
comments,
|
301
303
|
)
|
@@ -37,6 +37,19 @@ module RubyIndexer
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
class InstanceVariableTarget < Target
|
41
|
+
extend T::Sig
|
42
|
+
|
43
|
+
sig { returns(String) }
|
44
|
+
attr_reader :name
|
45
|
+
|
46
|
+
sig { params(name: String).void }
|
47
|
+
def initialize(name)
|
48
|
+
super()
|
49
|
+
@name = name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
class Reference
|
41
54
|
extend T::Sig
|
42
55
|
|
@@ -62,12 +75,14 @@ module RubyIndexer
|
|
62
75
|
target: Target,
|
63
76
|
index: RubyIndexer::Index,
|
64
77
|
dispatcher: Prism::Dispatcher,
|
78
|
+
uri: URI::Generic,
|
65
79
|
include_declarations: T::Boolean,
|
66
80
|
).void
|
67
81
|
end
|
68
|
-
def initialize(target, index, dispatcher, include_declarations: true)
|
82
|
+
def initialize(target, index, dispatcher, uri, include_declarations: true)
|
69
83
|
@target = target
|
70
84
|
@index = index
|
85
|
+
@uri = uri
|
71
86
|
@include_declarations = include_declarations
|
72
87
|
@stack = T.let([], T::Array[String])
|
73
88
|
@references = T.let([], T::Array[Reference])
|
@@ -94,6 +109,12 @@ module RubyIndexer
|
|
94
109
|
:on_constant_or_write_node_enter,
|
95
110
|
:on_constant_and_write_node_enter,
|
96
111
|
:on_constant_operator_write_node_enter,
|
112
|
+
:on_instance_variable_read_node_enter,
|
113
|
+
:on_instance_variable_write_node_enter,
|
114
|
+
:on_instance_variable_and_write_node_enter,
|
115
|
+
:on_instance_variable_operator_write_node_enter,
|
116
|
+
:on_instance_variable_or_write_node_enter,
|
117
|
+
:on_instance_variable_target_node_enter,
|
97
118
|
:on_call_node_enter,
|
98
119
|
)
|
99
120
|
end
|
@@ -107,15 +128,7 @@ module RubyIndexer
|
|
107
128
|
|
108
129
|
sig { params(node: Prism::ClassNode).void }
|
109
130
|
def on_class_node_enter(node)
|
110
|
-
|
111
|
-
name = constant_path.slice
|
112
|
-
nesting = actual_nesting(name)
|
113
|
-
|
114
|
-
if @target.is_a?(ConstTarget) && nesting.join("::") == @target.fully_qualified_name
|
115
|
-
@references << Reference.new(name, constant_path.location, declaration: true)
|
116
|
-
end
|
117
|
-
|
118
|
-
@stack << name
|
131
|
+
@stack << node.constant_path.slice
|
119
132
|
end
|
120
133
|
|
121
134
|
sig { params(node: Prism::ClassNode).void }
|
@@ -125,15 +138,7 @@ module RubyIndexer
|
|
125
138
|
|
126
139
|
sig { params(node: Prism::ModuleNode).void }
|
127
140
|
def on_module_node_enter(node)
|
128
|
-
|
129
|
-
name = constant_path.slice
|
130
|
-
nesting = actual_nesting(name)
|
131
|
-
|
132
|
-
if @target.is_a?(ConstTarget) && nesting.join("::") == @target.fully_qualified_name
|
133
|
-
@references << Reference.new(name, constant_path.location, declaration: true)
|
134
|
-
end
|
135
|
-
|
136
|
-
@stack << name
|
141
|
+
@stack << node.constant_path.slice
|
137
142
|
end
|
138
143
|
|
139
144
|
sig { params(node: Prism::ModuleNode).void }
|
@@ -156,7 +161,7 @@ module RubyIndexer
|
|
156
161
|
|
157
162
|
sig { params(node: Prism::ConstantPathNode).void }
|
158
163
|
def on_constant_path_node_enter(node)
|
159
|
-
name = constant_name(node)
|
164
|
+
name = Index.constant_name(node)
|
160
165
|
return unless name
|
161
166
|
|
162
167
|
collect_constant_references(name, node.location)
|
@@ -164,7 +169,7 @@ module RubyIndexer
|
|
164
169
|
|
165
170
|
sig { params(node: Prism::ConstantReadNode).void }
|
166
171
|
def on_constant_read_node_enter(node)
|
167
|
-
name = constant_name(node)
|
172
|
+
name = Index.constant_name(node)
|
168
173
|
return unless name
|
169
174
|
|
170
175
|
collect_constant_references(name, node.location)
|
@@ -185,7 +190,7 @@ module RubyIndexer
|
|
185
190
|
target = node.target
|
186
191
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
187
192
|
|
188
|
-
name = constant_name(target)
|
193
|
+
name = Index.constant_name(target)
|
189
194
|
return unless name
|
190
195
|
|
191
196
|
collect_constant_references(name, target.location)
|
@@ -196,7 +201,7 @@ module RubyIndexer
|
|
196
201
|
target = node.target
|
197
202
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
198
203
|
|
199
|
-
name = constant_name(target)
|
204
|
+
name = Index.constant_name(target)
|
200
205
|
return unless name
|
201
206
|
|
202
207
|
collect_constant_references(name, target.location)
|
@@ -207,7 +212,7 @@ module RubyIndexer
|
|
207
212
|
target = node.target
|
208
213
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
209
214
|
|
210
|
-
name = constant_name(target)
|
215
|
+
name = Index.constant_name(target)
|
211
216
|
return unless name
|
212
217
|
|
213
218
|
collect_constant_references(name, target.location)
|
@@ -218,7 +223,7 @@ module RubyIndexer
|
|
218
223
|
target = node.target
|
219
224
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
220
225
|
|
221
|
-
name = constant_name(target)
|
226
|
+
name = Index.constant_name(target)
|
222
227
|
return unless name
|
223
228
|
|
224
229
|
collect_constant_references(name, target.location)
|
@@ -262,6 +267,36 @@ module RubyIndexer
|
|
262
267
|
end
|
263
268
|
end
|
264
269
|
|
270
|
+
sig { params(node: Prism::InstanceVariableReadNode).void }
|
271
|
+
def on_instance_variable_read_node_enter(node)
|
272
|
+
collect_instance_variable_references(node.name.to_s, node.location, false)
|
273
|
+
end
|
274
|
+
|
275
|
+
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
276
|
+
def on_instance_variable_write_node_enter(node)
|
277
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
278
|
+
end
|
279
|
+
|
280
|
+
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
281
|
+
def on_instance_variable_and_write_node_enter(node)
|
282
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
283
|
+
end
|
284
|
+
|
285
|
+
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
286
|
+
def on_instance_variable_operator_write_node_enter(node)
|
287
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
288
|
+
end
|
289
|
+
|
290
|
+
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
291
|
+
def on_instance_variable_or_write_node_enter(node)
|
292
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
293
|
+
end
|
294
|
+
|
295
|
+
sig { params(node: Prism::InstanceVariableTargetNode).void }
|
296
|
+
def on_instance_variable_target_node_enter(node)
|
297
|
+
collect_instance_variable_references(node.name.to_s, node.location, true)
|
298
|
+
end
|
299
|
+
|
265
300
|
sig { params(node: Prism::CallNode).void }
|
266
301
|
def on_call_node_enter(node)
|
267
302
|
if @target.is_a?(MethodTarget) && (name = node.name.to_s) == @target.method_name
|
@@ -271,20 +306,6 @@ module RubyIndexer
|
|
271
306
|
|
272
307
|
private
|
273
308
|
|
274
|
-
sig { params(name: String).returns(T::Array[String]) }
|
275
|
-
def actual_nesting(name)
|
276
|
-
nesting = @stack + [name]
|
277
|
-
corrected_nesting = []
|
278
|
-
|
279
|
-
nesting.reverse_each do |name|
|
280
|
-
corrected_nesting.prepend(name.delete_prefix("::"))
|
281
|
-
|
282
|
-
break if name.start_with?("::")
|
283
|
-
end
|
284
|
-
|
285
|
-
corrected_nesting
|
286
|
-
end
|
287
|
-
|
288
309
|
sig { params(name: String, location: Prism::Location).void }
|
289
310
|
def collect_constant_references(name, location)
|
290
311
|
return unless @target.is_a?(ConstTarget)
|
@@ -292,33 +313,33 @@ module RubyIndexer
|
|
292
313
|
entries = @index.resolve(name, @stack)
|
293
314
|
return unless entries
|
294
315
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
316
|
+
# Filter down to all constant declarations that match the expected name and type
|
317
|
+
matching_entries = entries.select do |e|
|
318
|
+
[
|
319
|
+
Entry::Namespace,
|
320
|
+
Entry::Constant,
|
321
|
+
Entry::ConstantAlias,
|
322
|
+
Entry::UnresolvedConstantAlias,
|
323
|
+
].any? { |klass| e.is_a?(klass) } &&
|
324
|
+
e.name == @target.fully_qualified_name
|
325
|
+
end
|
299
326
|
|
300
|
-
|
301
|
-
# when we find the constant node defining the namespace, then we have to check if it wasn't already added
|
302
|
-
next if previous_reference&.location == location
|
327
|
+
return if matching_entries.empty?
|
303
328
|
|
304
|
-
|
329
|
+
# If any of the matching entries have the same location as the constant and were
|
330
|
+
# defined in the same file, then it is that constant's declaration
|
331
|
+
declaration = matching_entries.any? do |e|
|
332
|
+
e.uri == @uri && e.name_location == location
|
305
333
|
end
|
334
|
+
|
335
|
+
@references << Reference.new(name, location, declaration: declaration)
|
306
336
|
end
|
307
337
|
|
308
|
-
sig
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
Prism::ConstantPathTargetNode,
|
314
|
-
),
|
315
|
-
).returns(T.nilable(String))
|
316
|
-
end
|
317
|
-
def constant_name(node)
|
318
|
-
node.full_name
|
319
|
-
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
320
|
-
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
321
|
-
nil
|
338
|
+
sig { params(name: String, location: Prism::Location, declaration: T::Boolean).void }
|
339
|
+
def collect_instance_variable_references(name, location, declaration)
|
340
|
+
return unless @target.is_a?(InstanceVariableTarget) && name == @target.name
|
341
|
+
|
342
|
+
@references << Reference.new(name, location, declaration: declaration)
|
322
343
|
end
|
323
344
|
end
|
324
345
|
end
|
@@ -13,8 +13,15 @@ module URI
|
|
13
13
|
class << self
|
14
14
|
extend T::Sig
|
15
15
|
|
16
|
-
sig
|
17
|
-
|
16
|
+
sig do
|
17
|
+
params(
|
18
|
+
path: String,
|
19
|
+
fragment: T.nilable(String),
|
20
|
+
scheme: String,
|
21
|
+
load_path_entry: T.nilable(String),
|
22
|
+
).returns(URI::Generic)
|
23
|
+
end
|
24
|
+
def from_path(path:, fragment: nil, scheme: "file", load_path_entry: nil)
|
18
25
|
# On Windows, if the path begins with the disk name, we need to add a leading slash to make it a valid URI
|
19
26
|
escaped_path = if /^[A-Z]:/i.match?(path)
|
20
27
|
PARSER.escape("/#{path}")
|
@@ -25,10 +32,27 @@ module URI
|
|
25
32
|
PARSER.escape(path)
|
26
33
|
end
|
27
34
|
|
28
|
-
build(scheme: scheme, path: escaped_path, fragment: fragment)
|
35
|
+
uri = build(scheme: scheme, path: escaped_path, fragment: fragment)
|
36
|
+
|
37
|
+
if load_path_entry
|
38
|
+
uri.require_path = path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb")
|
39
|
+
end
|
40
|
+
|
41
|
+
uri
|
29
42
|
end
|
30
43
|
end
|
31
44
|
|
45
|
+
sig { returns(T.nilable(String)) }
|
46
|
+
attr_accessor :require_path
|
47
|
+
|
48
|
+
sig { params(load_path_entry: String).void }
|
49
|
+
def add_require_path_from_load_entry(load_path_entry)
|
50
|
+
path = to_standardized_path
|
51
|
+
return unless path
|
52
|
+
|
53
|
+
self.require_path = path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb")
|
54
|
+
end
|
55
|
+
|
32
56
|
sig { returns(T.nilable(String)) }
|
33
57
|
def to_standardized_path
|
34
58
|
parsed_path = path
|
@@ -44,5 +68,7 @@ module URI
|
|
44
68
|
unescaped_path
|
45
69
|
end
|
46
70
|
end
|
71
|
+
|
72
|
+
alias_method :full_path, :to_standardized_path
|
47
73
|
end
|
48
74
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyIndexer
|
5
|
+
# Represents the visibility scope in a Ruby namespace. This keeps track of whether methods are in a public, private or
|
6
|
+
# protected section, and whether they are module functions.
|
7
|
+
class VisibilityScope
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
class << self
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { returns(T.attached_class) }
|
14
|
+
def module_function_scope
|
15
|
+
new(module_func: true, visibility: Entry::Visibility::PRIVATE)
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { returns(T.attached_class) }
|
19
|
+
def public_scope
|
20
|
+
new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { returns(Entry::Visibility) }
|
25
|
+
attr_reader :visibility
|
26
|
+
|
27
|
+
sig { returns(T::Boolean) }
|
28
|
+
attr_reader :module_func
|
29
|
+
|
30
|
+
sig { params(visibility: Entry::Visibility, module_func: T::Boolean).void }
|
31
|
+
def initialize(visibility: Entry::Visibility::PUBLIC, module_func: false)
|
32
|
+
@visibility = visibility
|
33
|
+
@module_func = module_func
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -4,7 +4,8 @@
|
|
4
4
|
require "yaml"
|
5
5
|
require "did_you_mean"
|
6
6
|
|
7
|
-
require "ruby_indexer/lib/ruby_indexer/
|
7
|
+
require "ruby_indexer/lib/ruby_indexer/uri"
|
8
|
+
require "ruby_indexer/lib/ruby_indexer/visibility_scope"
|
8
9
|
require "ruby_indexer/lib/ruby_indexer/declaration_listener"
|
9
10
|
require "ruby_indexer/lib/ruby_indexer/reference_finder"
|
10
11
|
require "ruby_indexer/lib/ruby_indexer/enhancement"
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "test_case"
|
5
|
+
|
6
|
+
module RubyIndexer
|
7
|
+
class ClassVariableTest < TestCase
|
8
|
+
def test_class_variable_and_write
|
9
|
+
index(<<~RUBY)
|
10
|
+
class Foo
|
11
|
+
@@bar &&= 1
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
|
15
|
+
assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
|
16
|
+
|
17
|
+
entry = T.must(@index["@@bar"]&.first)
|
18
|
+
owner = T.must(entry.owner)
|
19
|
+
assert_instance_of(Entry::Class, owner)
|
20
|
+
assert_equal("Foo", owner.name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_class_variable_operator_write
|
24
|
+
index(<<~RUBY)
|
25
|
+
class Foo
|
26
|
+
@@bar += 1
|
27
|
+
end
|
28
|
+
RUBY
|
29
|
+
|
30
|
+
assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_class_variable_or_write
|
34
|
+
index(<<~RUBY)
|
35
|
+
class Foo
|
36
|
+
@@bar ||= 1
|
37
|
+
end
|
38
|
+
RUBY
|
39
|
+
|
40
|
+
assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_class_variable_target_node
|
44
|
+
index(<<~RUBY)
|
45
|
+
class Foo
|
46
|
+
@@foo, @@bar = 1
|
47
|
+
end
|
48
|
+
RUBY
|
49
|
+
|
50
|
+
assert_entry("@@foo", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
|
51
|
+
assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-9:1-14")
|
52
|
+
|
53
|
+
entry = T.must(@index["@@foo"]&.first)
|
54
|
+
owner = T.must(entry.owner)
|
55
|
+
assert_instance_of(Entry::Class, owner)
|
56
|
+
assert_equal("Foo", owner.name)
|
57
|
+
|
58
|
+
entry = T.must(@index["@@bar"]&.first)
|
59
|
+
owner = T.must(entry.owner)
|
60
|
+
assert_instance_of(Entry::Class, owner)
|
61
|
+
assert_equal("Foo", owner.name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_class_variable_write
|
65
|
+
index(<<~RUBY)
|
66
|
+
class Foo
|
67
|
+
@@bar = 1
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
|
71
|
+
assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_empty_name_class_variable
|
75
|
+
index(<<~RUBY)
|
76
|
+
module Foo
|
77
|
+
@@ = 1
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
refute_entry("@@")
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_top_level_class_variable
|
85
|
+
index(<<~RUBY)
|
86
|
+
@foo = 123
|
87
|
+
RUBY
|
88
|
+
|
89
|
+
entry = T.must(@index["@foo"]&.first)
|
90
|
+
assert_nil(entry.owner)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_class_variable_inside_self_method
|
94
|
+
index(<<~RUBY)
|
95
|
+
class Foo
|
96
|
+
def self.bar
|
97
|
+
@@bar = 123
|
98
|
+
end
|
99
|
+
end
|
100
|
+
RUBY
|
101
|
+
|
102
|
+
entry = T.must(@index["@@bar"]&.first)
|
103
|
+
owner = T.must(entry.owner)
|
104
|
+
assert_instance_of(Entry::Class, owner)
|
105
|
+
assert_equal("Foo", owner.name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_class_variable_inside_singleton_class
|
109
|
+
index(<<~RUBY)
|
110
|
+
class Foo
|
111
|
+
class << self
|
112
|
+
@@bar = 123
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
116
|
+
|
117
|
+
entry = T.must(@index["@@bar"]&.first)
|
118
|
+
owner = T.must(entry.owner)
|
119
|
+
assert_instance_of(Entry::Class, owner)
|
120
|
+
assert_equal("Foo", owner.name)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_class_variable_in_singleton_class_method
|
124
|
+
index(<<~RUBY)
|
125
|
+
class Foo
|
126
|
+
class << self
|
127
|
+
def self.bar
|
128
|
+
@@bar = 123
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
RUBY
|
133
|
+
|
134
|
+
entry = T.must(@index["@@bar"]&.first)
|
135
|
+
owner = T.must(entry.owner)
|
136
|
+
assert_instance_of(Entry::Class, owner)
|
137
|
+
assert_equal("Foo", owner.name)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -200,7 +200,7 @@ module RubyIndexer
|
|
200
200
|
|
201
201
|
assert_entry("Foo", Entry::Class, "/fake/path/foo.rb:0-0:1-3")
|
202
202
|
|
203
|
-
@index.delete(
|
203
|
+
@index.delete(URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
204
204
|
refute_entry("Foo")
|
205
205
|
|
206
206
|
assert_no_indexed_entries
|
@@ -618,10 +618,12 @@ module RubyIndexer
|
|
618
618
|
end
|
619
619
|
|
620
620
|
def test_lazy_comment_fetching_uses_correct_line_breaks_for_rendering
|
621
|
-
|
622
|
-
|
621
|
+
uri = URI::Generic.from_path(
|
622
|
+
load_path_entry: "#{Dir.pwd}/lib",
|
623
|
+
path: "#{Dir.pwd}/lib/ruby_lsp/node_context.rb",
|
624
|
+
)
|
623
625
|
|
624
|
-
@index.
|
626
|
+
@index.index_file(uri, collect_comments: false)
|
625
627
|
|
626
628
|
entry = @index["RubyLsp::NodeContext"].first
|
627
629
|
|
@@ -632,9 +634,12 @@ module RubyIndexer
|
|
632
634
|
end
|
633
635
|
|
634
636
|
def test_lazy_comment_fetching_does_not_fail_if_file_gets_deleted
|
635
|
-
|
637
|
+
uri = URI::Generic.from_path(
|
638
|
+
load_path_entry: "#{Dir.pwd}/lib",
|
639
|
+
path: "#{Dir.pwd}/lib/ruby_lsp/does_not_exist.rb",
|
640
|
+
)
|
636
641
|
|
637
|
-
@index.index_single(
|
642
|
+
@index.index_single(uri, <<~RUBY, collect_comments: false)
|
638
643
|
class Foo
|
639
644
|
end
|
640
645
|
RUBY
|
@@ -642,5 +647,24 @@ module RubyIndexer
|
|
642
647
|
entry = @index["Foo"].first
|
643
648
|
assert_empty(entry.comments)
|
644
649
|
end
|
650
|
+
|
651
|
+
def test_singleton_inside_compact_namespace
|
652
|
+
index(<<~RUBY)
|
653
|
+
module Foo::Bar
|
654
|
+
class << self
|
655
|
+
def baz; end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
RUBY
|
659
|
+
|
660
|
+
# Verify we didn't index the incorrect name
|
661
|
+
assert_nil(@index["Foo::Bar::<Class:Foo::Bar>"])
|
662
|
+
|
663
|
+
# Verify we indexed the correct name
|
664
|
+
assert_entry("Foo::Bar::<Class:Bar>", Entry::SingletonClass, "/fake/path/foo.rb:1-2:3-5")
|
665
|
+
|
666
|
+
method = @index["baz"]&.first
|
667
|
+
assert_equal("Foo::Bar::<Class:Bar>", method.owner.name)
|
668
|
+
end
|
645
669
|
end
|
646
670
|
end
|