ruby-lsp 0.16.5 → 0.16.7
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 +1 -1
- data/VERSION +1 -1
- data/exe/ruby-lsp +23 -2
- data/exe/ruby-lsp-check +1 -3
- data/exe/ruby-lsp-doctor +1 -4
- data/lib/core_ext/uri.rb +3 -0
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -0
- data/lib/ruby_indexer/lib/ruby_indexer/{collector.rb → declaration_listener.rb} +123 -126
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +5 -20
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +4 -2
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +51 -1
- data/lib/ruby_indexer/test/configuration_test.rb +8 -0
- data/lib/ruby_indexer/test/constant_test.rb +3 -0
- data/lib/ruby_indexer/test/method_test.rb +56 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +11 -0
- data/lib/ruby_lsp/listeners/completion.rb +76 -40
- data/lib/ruby_lsp/listeners/definition.rb +16 -7
- data/lib/ruby_lsp/listeners/document_highlight.rb +1 -1
- data/lib/ruby_lsp/listeners/document_link.rb +1 -1
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +59 -3
- data/lib/ruby_lsp/requests/completion.rb +2 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +17 -10
- data/lib/ruby_lsp/requests/definition.rb +23 -13
- data/lib/ruby_lsp/requests/hover.rb +11 -7
- data/lib/ruby_lsp/requests/request.rb +14 -0
- data/lib/ruby_lsp/requests/support/common.rb +20 -2
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebc166637de670ea02144e74ccb2e99ae1a9824c9f99995380d81bed99ff6a29
|
4
|
+
data.tar.gz: 48b7ef9364f4d1a8044042c8476414e87da5b38ca4871683c16d06636fc8e411
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80c4f791e7dfef66623f5190eaba4dc76c745a27f74238d912c34711c408803ec952d5ec3e8041ebb6410b99c74d2f3d8274db5dffa8f187e48a7032a3960086
|
7
|
+
data.tar.gz: 941209321fb263b9a22cbe27102e8761c6ef127902e2b74f760fec1a8701d96e5bcef5f01c704e7215e061437cac2577c38e100464cccfe03909aa42ee1e318e
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ The Ruby LSP features include
|
|
33
33
|
- Completion for classes, modules, constants and require paths
|
34
34
|
- Fuzzy search classes, modules and constants anywhere in the project and its dependencies (workspace symbol)
|
35
35
|
|
36
|
-
Adding method support for definition, completion, hover and workspace symbol is
|
36
|
+
Adding method support for definition, completion, hover and workspace symbol is partially supported, but not yet complete. Follow progress in https://github.com/Shopify/ruby-lsp/issues/899
|
37
37
|
|
38
38
|
See complete information about features [here](https://shopify.github.io/ruby-lsp/RubyLsp/Requests.html).
|
39
39
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.16.
|
1
|
+
0.16.7
|
data/exe/ruby-lsp
CHANGED
@@ -18,6 +18,10 @@ parser = OptionParser.new do |opts|
|
|
18
18
|
options[:debug] = true
|
19
19
|
end
|
20
20
|
|
21
|
+
opts.on("--time-index", "Measure the time it takes to index the project") do
|
22
|
+
options[:time_index] = true
|
23
|
+
end
|
24
|
+
|
21
25
|
opts.on(
|
22
26
|
"--branch [BRANCH]",
|
23
27
|
"Launch the Ruby LSP using the specified branch rather than the release version",
|
@@ -75,15 +79,32 @@ require "ruby_lsp/internal"
|
|
75
79
|
|
76
80
|
if options[:debug]
|
77
81
|
if ["x64-mingw-ucrt", "x64-mingw32"].include?(RUBY_PLATFORM)
|
78
|
-
puts "Debugging is not supported on Windows"
|
82
|
+
$stderr.puts "Debugging is not supported on Windows"
|
79
83
|
exit 1
|
80
84
|
end
|
81
85
|
|
82
86
|
begin
|
87
|
+
ENV.delete("RUBY_DEBUG_IRB_CONSOLE")
|
83
88
|
require "debug/open_nonstop"
|
84
89
|
rescue LoadError
|
85
|
-
|
90
|
+
$stderr.puts("You need to install the debug gem to use the --debug flag")
|
86
91
|
end
|
87
92
|
end
|
88
93
|
|
94
|
+
if options[:time_index]
|
95
|
+
require "benchmark"
|
96
|
+
|
97
|
+
index = RubyIndexer::Index.new
|
98
|
+
|
99
|
+
result = Benchmark.realtime { index.index_all }
|
100
|
+
entries = index.instance_variable_get(:@entries)
|
101
|
+
entries_by_entry_type = entries.values.flatten.group_by(&:class)
|
102
|
+
|
103
|
+
puts <<~MSG
|
104
|
+
Ruby LSP v#{RubyLsp::VERSION}: Indexing took #{result.round(5)} seconds and generated:
|
105
|
+
- #{entries_by_entry_type.map { |k, v| "#{k.name.split("::").last}: #{v.size}" }.join("\n- ")}
|
106
|
+
MSG
|
107
|
+
return
|
108
|
+
end
|
109
|
+
|
89
110
|
RubyLsp::Server.new.start
|
data/exe/ruby-lsp-check
CHANGED
@@ -47,9 +47,7 @@ index = RubyIndexer::Index.new
|
|
47
47
|
indexables = RubyIndexer.configuration.indexables
|
48
48
|
|
49
49
|
indexables.each_with_index do |indexable, i|
|
50
|
-
|
51
|
-
collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
|
52
|
-
collector.collect(result.value)
|
50
|
+
index.index_single(indexable)
|
53
51
|
rescue => e
|
54
52
|
errors[indexable.full_path] = e
|
55
53
|
ensure
|
data/exe/ruby-lsp-doctor
CHANGED
@@ -19,8 +19,5 @@ puts "Globbing for indexable files"
|
|
19
19
|
|
20
20
|
RubyIndexer.configuration.indexables.each do |indexable|
|
21
21
|
puts "indexing: #{indexable.full_path}"
|
22
|
-
|
23
|
-
result = Prism.parse(content)
|
24
|
-
collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
|
25
|
-
collector.collect(result.value)
|
22
|
+
index.index_single(indexable)
|
26
23
|
end
|
data/lib/core_ext/uri.rb
CHANGED
@@ -11,6 +11,9 @@ module URI
|
|
11
11
|
# On Windows, if the path begins with the disk name, we need to add a leading slash to make it a valid URI
|
12
12
|
escaped_path = if /^[A-Z]:/i.match?(path)
|
13
13
|
DEFAULT_PARSER.escape("/#{path}")
|
14
|
+
elsif path.start_with?("//?/")
|
15
|
+
# Some paths on Windows start with "//?/". This is a special prefix that allows for long file paths
|
16
|
+
DEFAULT_PARSER.escape(path.delete_prefix("//?"))
|
14
17
|
else
|
15
18
|
DEFAULT_PARSER.escape(path)
|
16
19
|
end
|
@@ -56,6 +56,7 @@ module RubyIndexer
|
|
56
56
|
load_path_entry = T.let(nil, T.nilable(String))
|
57
57
|
|
58
58
|
Dir.glob(pattern, File::FNM_PATHNAME | File::FNM_EXTGLOB).map! do |path|
|
59
|
+
path = File.expand_path(path)
|
59
60
|
# All entries for the same pattern match the same $LOAD_PATH entry. Since searching the $LOAD_PATH for every
|
60
61
|
# entry is expensive, we memoize it until we find a path that doesn't belong to that $LOAD_PATH. This happens
|
61
62
|
# on repositories that define multiple gems, like Rails. All frameworks are defined inside the Dir.pwd, but
|
@@ -2,79 +2,103 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module RubyIndexer
|
5
|
-
class
|
5
|
+
class DeclarationListener
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(index, parse_result, file_path)
|
8
|
+
sig do
|
9
|
+
params(index: Index, dispatcher: Prism::Dispatcher, parse_result: Prism::ParseResult, file_path: String).void
|
10
|
+
end
|
11
|
+
def initialize(index, dispatcher, parse_result, file_path)
|
12
12
|
@index = index
|
13
13
|
@file_path = file_path
|
14
|
-
@stack = T.let([], T::Array[String])
|
15
14
|
@comments_by_line = T.let(
|
16
15
|
parse_result.comments.to_h do |c|
|
17
16
|
[c.location.start_line, c]
|
18
17
|
end,
|
19
18
|
T::Hash[Integer, Prism::Comment],
|
20
19
|
)
|
21
|
-
@
|
22
|
-
|
20
|
+
@inside_def = T.let(false, T::Boolean)
|
21
|
+
|
22
|
+
# The nesting stack we're currently inside. Used to determine the fully qualified name of constants, but only
|
23
|
+
# stored by unresolved aliases which need the original nesting to be lazily resolved
|
24
|
+
@stack = T.let([], T::Array[String])
|
23
25
|
|
24
|
-
|
26
|
+
# A stack of namespace entries that represent where we currently are. Used to properly assign methods to an owner
|
27
|
+
@owner_stack = T.let([], T::Array[Entry::Namespace])
|
28
|
+
|
29
|
+
dispatcher.register(
|
30
|
+
self,
|
31
|
+
:on_class_node_enter,
|
32
|
+
:on_class_node_leave,
|
33
|
+
:on_module_node_enter,
|
34
|
+
:on_module_node_leave,
|
35
|
+
:on_def_node_enter,
|
36
|
+
:on_def_node_leave,
|
37
|
+
:on_call_node_enter,
|
38
|
+
:on_multi_write_node_enter,
|
39
|
+
:on_constant_path_write_node_enter,
|
40
|
+
:on_constant_path_or_write_node_enter,
|
41
|
+
:on_constant_path_operator_write_node_enter,
|
42
|
+
:on_constant_path_and_write_node_enter,
|
43
|
+
:on_constant_or_write_node_enter,
|
44
|
+
:on_constant_write_node_enter,
|
45
|
+
:on_constant_or_write_node_enter,
|
46
|
+
:on_constant_and_write_node_enter,
|
47
|
+
:on_constant_operator_write_node_enter,
|
48
|
+
)
|
25
49
|
end
|
26
50
|
|
27
|
-
sig { params(node: Prism::
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
when Prism::StatementsNode
|
38
|
-
T.unsafe(@queue).prepend(*node_or_event.body)
|
39
|
-
when Prism::ClassNode
|
40
|
-
add_class_entry(node_or_event)
|
41
|
-
when Prism::ModuleNode
|
42
|
-
add_module_entry(node_or_event)
|
43
|
-
when Prism::MultiWriteNode
|
44
|
-
handle_multi_write_node(node_or_event)
|
45
|
-
when Prism::ConstantPathWriteNode
|
46
|
-
handle_constant_path_write_node(node_or_event)
|
47
|
-
when Prism::ConstantPathOrWriteNode
|
48
|
-
handle_constant_path_or_write_node(node_or_event)
|
49
|
-
when Prism::ConstantPathOperatorWriteNode
|
50
|
-
handle_constant_path_operator_write_node(node_or_event)
|
51
|
-
when Prism::ConstantPathAndWriteNode
|
52
|
-
handle_constant_path_and_write_node(node_or_event)
|
53
|
-
when Prism::ConstantWriteNode
|
54
|
-
handle_constant_write_node(node_or_event)
|
55
|
-
when Prism::ConstantOrWriteNode
|
56
|
-
name = fully_qualify_name(node_or_event.name.to_s)
|
57
|
-
add_constant(node_or_event, name)
|
58
|
-
when Prism::ConstantAndWriteNode
|
59
|
-
name = fully_qualify_name(node_or_event.name.to_s)
|
60
|
-
add_constant(node_or_event, name)
|
61
|
-
when Prism::ConstantOperatorWriteNode
|
62
|
-
name = fully_qualify_name(node_or_event.name.to_s)
|
63
|
-
add_constant(node_or_event, name)
|
64
|
-
when Prism::CallNode
|
65
|
-
handle_call_node(node_or_event)
|
66
|
-
when Prism::DefNode
|
67
|
-
handle_def_node(node_or_event)
|
68
|
-
when LEAVE_EVENT
|
69
|
-
@stack.pop
|
70
|
-
end
|
51
|
+
sig { params(node: Prism::ClassNode).void }
|
52
|
+
def on_class_node_enter(node)
|
53
|
+
name = node.constant_path.location.slice
|
54
|
+
|
55
|
+
comments = collect_comments(node)
|
56
|
+
|
57
|
+
superclass = node.superclass
|
58
|
+
parent_class = case superclass
|
59
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
60
|
+
superclass.slice
|
71
61
|
end
|
62
|
+
|
63
|
+
entry = Entry::Class.new(
|
64
|
+
fully_qualify_name(name),
|
65
|
+
@file_path,
|
66
|
+
node.location,
|
67
|
+
comments,
|
68
|
+
parent_class,
|
69
|
+
)
|
70
|
+
|
71
|
+
@owner_stack << entry
|
72
|
+
@index << entry
|
73
|
+
@stack << name
|
72
74
|
end
|
73
75
|
|
74
|
-
|
76
|
+
sig { params(node: Prism::ClassNode).void }
|
77
|
+
def on_class_node_leave(node)
|
78
|
+
@stack.pop
|
79
|
+
@owner_stack.pop
|
80
|
+
end
|
81
|
+
|
82
|
+
sig { params(node: Prism::ModuleNode).void }
|
83
|
+
def on_module_node_enter(node)
|
84
|
+
name = node.constant_path.location.slice
|
85
|
+
|
86
|
+
comments = collect_comments(node)
|
87
|
+
entry = Entry::Module.new(fully_qualify_name(name), @file_path, node.location, comments)
|
88
|
+
|
89
|
+
@owner_stack << entry
|
90
|
+
@index << entry
|
91
|
+
@stack << name
|
92
|
+
end
|
93
|
+
|
94
|
+
sig { params(node: Prism::ModuleNode).void }
|
95
|
+
def on_module_node_leave(node)
|
96
|
+
@stack.pop
|
97
|
+
@owner_stack.pop
|
98
|
+
end
|
75
99
|
|
76
100
|
sig { params(node: Prism::MultiWriteNode).void }
|
77
|
-
def
|
101
|
+
def on_multi_write_node_enter(node)
|
78
102
|
value = node.value
|
79
103
|
values = value.is_a?(Prism::ArrayNode) && value.opening_loc ? value.elements : []
|
80
104
|
|
@@ -94,7 +118,7 @@ module RubyIndexer
|
|
94
118
|
end
|
95
119
|
|
96
120
|
sig { params(node: Prism::ConstantPathWriteNode).void }
|
97
|
-
def
|
121
|
+
def on_constant_path_write_node_enter(node)
|
98
122
|
# ignore variable constants like `var::FOO` or `self.class::FOO`
|
99
123
|
target = node.target
|
100
124
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
@@ -104,7 +128,7 @@ module RubyIndexer
|
|
104
128
|
end
|
105
129
|
|
106
130
|
sig { params(node: Prism::ConstantPathOrWriteNode).void }
|
107
|
-
def
|
131
|
+
def on_constant_path_or_write_node_enter(node)
|
108
132
|
# ignore variable constants like `var::FOO` or `self.class::FOO`
|
109
133
|
target = node.target
|
110
134
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
@@ -114,7 +138,7 @@ module RubyIndexer
|
|
114
138
|
end
|
115
139
|
|
116
140
|
sig { params(node: Prism::ConstantPathOperatorWriteNode).void }
|
117
|
-
def
|
141
|
+
def on_constant_path_operator_write_node_enter(node)
|
118
142
|
# ignore variable constants like `var::FOO` or `self.class::FOO`
|
119
143
|
target = node.target
|
120
144
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
@@ -124,7 +148,7 @@ module RubyIndexer
|
|
124
148
|
end
|
125
149
|
|
126
150
|
sig { params(node: Prism::ConstantPathAndWriteNode).void }
|
127
|
-
def
|
151
|
+
def on_constant_path_and_write_node_enter(node)
|
128
152
|
# ignore variable constants like `var::FOO` or `self.class::FOO`
|
129
153
|
target = node.target
|
130
154
|
return unless target.parent.nil? || target.parent.is_a?(Prism::ConstantReadNode)
|
@@ -134,13 +158,31 @@ module RubyIndexer
|
|
134
158
|
end
|
135
159
|
|
136
160
|
sig { params(node: Prism::ConstantWriteNode).void }
|
137
|
-
def
|
161
|
+
def on_constant_write_node_enter(node)
|
162
|
+
name = fully_qualify_name(node.name.to_s)
|
163
|
+
add_constant(node, name)
|
164
|
+
end
|
165
|
+
|
166
|
+
sig { params(node: Prism::ConstantOrWriteNode).void }
|
167
|
+
def on_constant_or_write_node_enter(node)
|
168
|
+
name = fully_qualify_name(node.name.to_s)
|
169
|
+
add_constant(node, name)
|
170
|
+
end
|
171
|
+
|
172
|
+
sig { params(node: Prism::ConstantAndWriteNode).void }
|
173
|
+
def on_constant_and_write_node_enter(node)
|
174
|
+
name = fully_qualify_name(node.name.to_s)
|
175
|
+
add_constant(node, name)
|
176
|
+
end
|
177
|
+
|
178
|
+
sig { params(node: Prism::ConstantOperatorWriteNode).void }
|
179
|
+
def on_constant_operator_write_node_enter(node)
|
138
180
|
name = fully_qualify_name(node.name.to_s)
|
139
181
|
add_constant(node, name)
|
140
182
|
end
|
141
183
|
|
142
184
|
sig { params(node: Prism::CallNode).void }
|
143
|
-
def
|
185
|
+
def on_call_node_enter(node)
|
144
186
|
message = node.name
|
145
187
|
|
146
188
|
case message
|
@@ -153,14 +195,15 @@ module RubyIndexer
|
|
153
195
|
when :attr_accessor
|
154
196
|
handle_attribute(node, reader: true, writer: true)
|
155
197
|
when :include
|
156
|
-
|
198
|
+
handle_module_operation(node, :included_modules)
|
157
199
|
when :prepend
|
158
|
-
|
200
|
+
handle_module_operation(node, :prepended_modules)
|
159
201
|
end
|
160
202
|
end
|
161
203
|
|
162
204
|
sig { params(node: Prism::DefNode).void }
|
163
|
-
def
|
205
|
+
def on_def_node_enter(node)
|
206
|
+
@inside_def = true
|
164
207
|
method_name = node.name.to_s
|
165
208
|
comments = collect_comments(node)
|
166
209
|
case node.receiver
|
@@ -171,7 +214,7 @@ module RubyIndexer
|
|
171
214
|
node.location,
|
172
215
|
comments,
|
173
216
|
node.parameters,
|
174
|
-
@
|
217
|
+
@owner_stack.last,
|
175
218
|
)
|
176
219
|
when Prism::SelfNode
|
177
220
|
@index << Entry::SingletonMethod.new(
|
@@ -180,11 +223,18 @@ module RubyIndexer
|
|
180
223
|
node.location,
|
181
224
|
comments,
|
182
225
|
node.parameters,
|
183
|
-
@
|
226
|
+
@owner_stack.last,
|
184
227
|
)
|
185
228
|
end
|
186
229
|
end
|
187
230
|
|
231
|
+
sig { params(node: Prism::DefNode).void }
|
232
|
+
def on_def_node_leave(node)
|
233
|
+
@inside_def = false
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
|
188
238
|
sig { params(node: Prism::CallNode).void }
|
189
239
|
def handle_private_constant(node)
|
190
240
|
arguments = node.arguments&.arguments
|
@@ -240,62 +290,16 @@ module RubyIndexer
|
|
240
290
|
|
241
291
|
# If the right hand side is another constant assignment, we need to visit it because that constant has to be
|
242
292
|
# indexed too
|
243
|
-
@queue.prepend(value)
|
244
293
|
Entry::UnresolvedAlias.new(value.name.to_s, @stack.dup, name, @file_path, node.location, comments)
|
245
294
|
when Prism::ConstantPathWriteNode, Prism::ConstantPathOrWriteNode, Prism::ConstantPathOperatorWriteNode,
|
246
295
|
Prism::ConstantPathAndWriteNode
|
247
296
|
|
248
|
-
@queue.prepend(value)
|
249
297
|
Entry::UnresolvedAlias.new(value.target.slice, @stack.dup, name, @file_path, node.location, comments)
|
250
298
|
else
|
251
299
|
Entry::Constant.new(name, @file_path, node.location, comments)
|
252
300
|
end
|
253
301
|
end
|
254
302
|
|
255
|
-
sig { params(node: Prism::ModuleNode).void }
|
256
|
-
def add_module_entry(node)
|
257
|
-
name = node.constant_path.location.slice
|
258
|
-
unless /^[A-Z:]/.match?(name)
|
259
|
-
@queue << node.body
|
260
|
-
return
|
261
|
-
end
|
262
|
-
|
263
|
-
comments = collect_comments(node)
|
264
|
-
@current_owner = Entry::Module.new(fully_qualify_name(name), @file_path, node.location, comments)
|
265
|
-
@index << @current_owner
|
266
|
-
@stack << name
|
267
|
-
@queue.prepend(node.body, LEAVE_EVENT)
|
268
|
-
end
|
269
|
-
|
270
|
-
sig { params(node: Prism::ClassNode).void }
|
271
|
-
def add_class_entry(node)
|
272
|
-
name = node.constant_path.location.slice
|
273
|
-
|
274
|
-
unless /^[A-Z:]/.match?(name)
|
275
|
-
@queue << node.body
|
276
|
-
return
|
277
|
-
end
|
278
|
-
|
279
|
-
comments = collect_comments(node)
|
280
|
-
|
281
|
-
superclass = node.superclass
|
282
|
-
parent_class = case superclass
|
283
|
-
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
284
|
-
superclass.slice
|
285
|
-
end
|
286
|
-
|
287
|
-
@current_owner = Entry::Class.new(
|
288
|
-
fully_qualify_name(name),
|
289
|
-
@file_path,
|
290
|
-
node.location,
|
291
|
-
comments,
|
292
|
-
parent_class,
|
293
|
-
)
|
294
|
-
@index << @current_owner
|
295
|
-
@stack << name
|
296
|
-
@queue.prepend(node.body, LEAVE_EVENT)
|
297
|
-
end
|
298
|
-
|
299
303
|
sig { params(node: Prism::Node).returns(T::Array[String]) }
|
300
304
|
def collect_comments(node)
|
301
305
|
comments = []
|
@@ -350,24 +354,17 @@ module RubyIndexer
|
|
350
354
|
|
351
355
|
next unless name && loc
|
352
356
|
|
353
|
-
@index << Entry::Accessor.new(name, @file_path, loc, comments, @
|
354
|
-
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @
|
357
|
+
@index << Entry::Accessor.new(name, @file_path, loc, comments, @owner_stack.last) if reader
|
358
|
+
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @owner_stack.last) if writer
|
355
359
|
end
|
356
360
|
end
|
357
361
|
|
358
|
-
sig { params(node: Prism::CallNode).void }
|
359
|
-
def handle_include(node)
|
360
|
-
handle_module_operation(node, :included_modules)
|
361
|
-
end
|
362
|
-
|
363
|
-
sig { params(node: Prism::CallNode).void }
|
364
|
-
def handle_prepend(node)
|
365
|
-
handle_module_operation(node, :prepended_modules)
|
366
|
-
end
|
367
|
-
|
368
362
|
sig { params(node: Prism::CallNode, operation: Symbol).void }
|
369
363
|
def handle_module_operation(node, operation)
|
370
|
-
return
|
364
|
+
return if @inside_def
|
365
|
+
|
366
|
+
owner = @owner_stack.last
|
367
|
+
return unless owner
|
371
368
|
|
372
369
|
arguments = node.arguments&.arguments
|
373
370
|
return unless arguments
|
@@ -381,7 +378,7 @@ module RubyIndexer
|
|
381
378
|
# If a constant path reference is dynamic or missing parts, we can't
|
382
379
|
# index it
|
383
380
|
end
|
384
|
-
collection = operation == :included_modules ?
|
381
|
+
collection = operation == :included_modules ? owner.included_modules : owner.prepended_modules
|
385
382
|
collection.concat(names)
|
386
383
|
end
|
387
384
|
end
|
@@ -61,28 +61,13 @@ module RubyIndexer
|
|
61
61
|
abstract!
|
62
62
|
|
63
63
|
sig { returns(T::Array[String]) }
|
64
|
-
|
65
|
-
|
66
|
-
sig { returns(T::Array[String]) }
|
67
|
-
attr_accessor :prepended_modules
|
68
|
-
|
69
|
-
sig do
|
70
|
-
params(
|
71
|
-
name: String,
|
72
|
-
file_path: String,
|
73
|
-
location: T.any(Prism::Location, RubyIndexer::Location),
|
74
|
-
comments: T::Array[String],
|
75
|
-
).void
|
76
|
-
end
|
77
|
-
def initialize(name, file_path, location, comments)
|
78
|
-
super(name, file_path, location, comments)
|
79
|
-
@included_modules = T.let([], T::Array[String])
|
80
|
-
@prepended_modules = T.let([], T::Array[String])
|
64
|
+
def included_modules
|
65
|
+
@included_modules ||= T.let([], T.nilable(T::Array[String]))
|
81
66
|
end
|
82
67
|
|
83
|
-
sig { returns(String) }
|
84
|
-
def
|
85
|
-
T.
|
68
|
+
sig { returns(T::Array[String]) }
|
69
|
+
def prepended_modules
|
70
|
+
@prepended_modules ||= T.let([], T.nilable(T::Array[String]))
|
86
71
|
end
|
87
72
|
end
|
88
73
|
|
@@ -185,9 +185,11 @@ module RubyIndexer
|
|
185
185
|
sig { params(indexable_path: IndexablePath, source: T.nilable(String)).void }
|
186
186
|
def index_single(indexable_path, source = nil)
|
187
187
|
content = source || File.read(indexable_path.full_path)
|
188
|
+
dispatcher = Prism::Dispatcher.new
|
189
|
+
|
188
190
|
result = Prism.parse(content)
|
189
|
-
|
190
|
-
|
191
|
+
DeclarationListener.new(self, dispatcher, result, indexable_path.full_path)
|
192
|
+
dispatcher.dispatch(result.value)
|
191
193
|
|
192
194
|
require_path = indexable_path.require_path
|
193
195
|
@require_paths_tree.insert(require_path, indexable_path) if require_path
|
@@ -5,7 +5,7 @@ require "yaml"
|
|
5
5
|
require "did_you_mean"
|
6
6
|
|
7
7
|
require "ruby_indexer/lib/ruby_indexer/indexable_path"
|
8
|
-
require "ruby_indexer/lib/ruby_indexer/
|
8
|
+
require "ruby_indexer/lib/ruby_indexer/declaration_listener"
|
9
9
|
require "ruby_indexer/lib/ruby_indexer/index"
|
10
10
|
require "ruby_indexer/lib/ruby_indexer/entry"
|
11
11
|
require "ruby_indexer/lib/ruby_indexer/configuration"
|
@@ -14,6 +14,15 @@ module RubyIndexer
|
|
14
14
|
assert_entry("Foo", Entry::Class, "/fake/path/foo.rb:0-0:1-3")
|
15
15
|
end
|
16
16
|
|
17
|
+
def test_conditional_class
|
18
|
+
index(<<~RUBY)
|
19
|
+
class Foo
|
20
|
+
end if condition
|
21
|
+
RUBY
|
22
|
+
|
23
|
+
assert_entry("Foo", Entry::Class, "/fake/path/foo.rb:0-0:1-3")
|
24
|
+
end
|
25
|
+
|
17
26
|
def test_class_with_statements
|
18
27
|
index(<<~RUBY)
|
19
28
|
class Foo
|
@@ -60,7 +69,23 @@ module RubyIndexer
|
|
60
69
|
end
|
61
70
|
RUBY
|
62
71
|
|
72
|
+
assert_entry("self::Bar", Entry::Class, "/fake/path/foo.rb:0-0:1-3")
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_dynamically_namespaced_class_doesnt_affect_other_classes
|
76
|
+
index(<<~RUBY)
|
77
|
+
class Foo
|
78
|
+
class self::Bar
|
79
|
+
end
|
80
|
+
|
81
|
+
class Bar
|
82
|
+
end
|
83
|
+
end
|
84
|
+
RUBY
|
85
|
+
|
63
86
|
refute_entry("self::Bar")
|
87
|
+
assert_entry("Foo", Entry::Class, "/fake/path/foo.rb:0-0:6-3")
|
88
|
+
assert_entry("Foo::Bar", Entry::Class, "/fake/path/foo.rb:4-2:5-5")
|
64
89
|
end
|
65
90
|
|
66
91
|
def test_empty_statements_module
|
@@ -72,6 +97,15 @@ module RubyIndexer
|
|
72
97
|
assert_entry("Foo", Entry::Module, "/fake/path/foo.rb:0-0:1-3")
|
73
98
|
end
|
74
99
|
|
100
|
+
def test_conditional_module
|
101
|
+
index(<<~RUBY)
|
102
|
+
module Foo
|
103
|
+
end if condition
|
104
|
+
RUBY
|
105
|
+
|
106
|
+
assert_entry("Foo", Entry::Module, "/fake/path/foo.rb:0-0:1-3")
|
107
|
+
end
|
108
|
+
|
75
109
|
def test_module_with_statements
|
76
110
|
index(<<~RUBY)
|
77
111
|
module Foo
|
@@ -106,7 +140,23 @@ module RubyIndexer
|
|
106
140
|
end
|
107
141
|
RUBY
|
108
142
|
|
109
|
-
|
143
|
+
assert_entry("self::Bar", Entry::Module, "/fake/path/foo.rb:0-0:1-3")
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_dynamically_namespaced_module_doesnt_affect_other_modules
|
147
|
+
index(<<~RUBY)
|
148
|
+
module Foo
|
149
|
+
class self::Bar
|
150
|
+
end
|
151
|
+
|
152
|
+
module Bar
|
153
|
+
end
|
154
|
+
end
|
155
|
+
RUBY
|
156
|
+
|
157
|
+
assert_entry("Foo::self::Bar", Entry::Class, "/fake/path/foo.rb:1-2:2-5")
|
158
|
+
assert_entry("Foo", Entry::Module, "/fake/path/foo.rb:0-0:6-3")
|
159
|
+
assert_entry("Foo::Bar", Entry::Module, "/fake/path/foo.rb:4-2:5-5")
|
110
160
|
end
|
111
161
|
|
112
162
|
def test_nested_modules_and_classes
|
@@ -20,6 +20,14 @@ module RubyIndexer
|
|
20
20
|
assert(indexables.none? { |indexable| indexable.full_path == __FILE__ })
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_indexables_have_expanded_full_paths
|
24
|
+
@config.apply_config({ "included_patterns" => ["**/*.rb"] })
|
25
|
+
indexables = @config.indexables
|
26
|
+
|
27
|
+
# All paths should be expanded
|
28
|
+
assert(indexables.none? { |indexable| indexable.full_path.start_with?("lib/") })
|
29
|
+
end
|
30
|
+
|
23
31
|
def test_indexables_only_includes_gem_require_paths
|
24
32
|
indexables = @config.indexables
|
25
33
|
|
@@ -12,10 +12,13 @@ module RubyIndexer
|
|
12
12
|
class ::Bar
|
13
13
|
FOO = 2
|
14
14
|
end
|
15
|
+
|
16
|
+
BAR = 3 if condition
|
15
17
|
RUBY
|
16
18
|
|
17
19
|
assert_entry("FOO", Entry::Constant, "/fake/path/foo.rb:0-0:0-7")
|
18
20
|
assert_entry("Bar::FOO", Entry::Constant, "/fake/path/foo.rb:3-2:3-9")
|
21
|
+
assert_entry("BAR", Entry::Constant, "/fake/path/foo.rb:6-0:6-7")
|
19
22
|
end
|
20
23
|
|
21
24
|
def test_constant_or_writes
|