steep 1.10.0.pre.3 → 2.0.0
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/CHANGELOG.md +87 -0
- data/CLAUDE.md +114 -0
- data/README.md +1 -1
- data/Rakefile +15 -3
- data/Steepfile +13 -13
- data/lib/steep/annotation_parser.rb +5 -1
- data/lib/steep/annotations_helper.rb +12 -2
- data/lib/steep/ast/node/type_application.rb +22 -16
- data/lib/steep/ast/node/type_assertion.rb +7 -4
- data/lib/steep/ast/types/factory.rb +3 -2
- data/lib/steep/cli.rb +246 -2
- data/lib/steep/daemon/configuration.rb +19 -0
- data/lib/steep/daemon/server.rb +476 -0
- data/lib/steep/daemon.rb +201 -0
- data/lib/steep/diagnostic/ruby.rb +50 -8
- data/lib/steep/diagnostic/signature.rb +31 -8
- data/lib/steep/drivers/check.rb +301 -140
- data/lib/steep/drivers/print_project.rb +9 -10
- data/lib/steep/drivers/query.rb +102 -0
- data/lib/steep/drivers/start_server.rb +19 -0
- data/lib/steep/drivers/stop_server.rb +20 -0
- data/lib/steep/drivers/watch.rb +2 -2
- data/lib/steep/index/rbs_index.rb +38 -13
- data/lib/steep/index/signature_symbol_provider.rb +24 -3
- data/lib/steep/interface/builder.rb +48 -15
- data/lib/steep/interface/shape.rb +13 -5
- data/lib/steep/locator.rb +377 -0
- data/lib/steep/project/dsl.rb +26 -5
- data/lib/steep/project/group.rb +8 -2
- data/lib/steep/project/target.rb +16 -2
- data/lib/steep/project.rb +21 -2
- data/lib/steep/server/base_worker.rb +2 -2
- data/lib/steep/server/change_buffer.rb +2 -1
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/inline_source_change_detector.rb +94 -0
- data/lib/steep/server/interaction_worker.rb +51 -74
- data/lib/steep/server/lsp_formatter.rb +48 -12
- data/lib/steep/server/master.rb +100 -18
- data/lib/steep/server/target_group_files.rb +124 -151
- data/lib/steep/server/type_check_controller.rb +276 -123
- data/lib/steep/server/type_check_worker.rb +104 -3
- data/lib/steep/services/completion_provider/rbs.rb +74 -0
- data/lib/steep/services/completion_provider/ruby.rb +652 -0
- data/lib/steep/services/completion_provider/type_name.rb +243 -0
- data/lib/steep/services/completion_provider.rb +39 -662
- data/lib/steep/services/content_change.rb +14 -1
- data/lib/steep/services/file_loader.rb +4 -2
- data/lib/steep/services/goto_service.rb +271 -68
- data/lib/steep/services/hover_provider/content.rb +67 -0
- data/lib/steep/services/hover_provider/rbs.rb +8 -9
- data/lib/steep/services/hover_provider/ruby.rb +123 -64
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
- data/lib/steep/services/signature_service.rb +129 -54
- data/lib/steep/services/type_check_service.rb +72 -27
- data/lib/steep/signature/validator.rb +30 -18
- data/lib/steep/source/ignore_ranges.rb +14 -4
- data/lib/steep/source.rb +16 -2
- data/lib/steep/tagged_logging.rb +39 -0
- data/lib/steep/type_construction.rb +94 -21
- data/lib/steep/type_inference/block_params.rb +7 -7
- data/lib/steep/type_inference/context.rb +4 -2
- data/lib/steep/type_inference/logic_type_interpreter.rb +21 -3
- data/lib/steep/type_inference/method_call.rb +4 -0
- data/lib/steep/type_inference/type_env.rb +1 -1
- data/lib/steep/typing.rb +0 -2
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +42 -32
- data/manual/ruby-diagnostics.md +67 -0
- data/sample/Steepfile +1 -0
- data/sample/lib/conference.rb +1 -0
- data/sample/lib/deprecated.rb +6 -0
- data/sample/lib/inline.rb +43 -0
- data/sample/sig/generics.rbs +3 -0
- data/steep.gemspec +4 -5
- metadata +26 -26
- data/lib/steep/services/type_name_completion.rb +0 -236
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module Steep
|
|
2
2
|
module Services
|
|
3
|
-
|
|
4
|
-
include NodeHelper
|
|
5
|
-
|
|
3
|
+
module CompletionProvider
|
|
6
4
|
Position = _ = Struct.new(:line, :column, keyword_init: true) do
|
|
7
5
|
# @implements Position
|
|
8
6
|
def -(size)
|
|
@@ -28,11 +26,18 @@ module Steep
|
|
|
28
26
|
|
|
29
27
|
def comments
|
|
30
28
|
case entry = env.constant_entry(full_name)
|
|
31
|
-
when RBS::Environment::ConstantEntry
|
|
29
|
+
when ::RBS::Environment::ConstantEntry
|
|
32
30
|
[entry.decl.comment]
|
|
33
|
-
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
34
|
-
entry.
|
|
35
|
-
|
|
31
|
+
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
32
|
+
entry.each_decl.map do |decl|
|
|
33
|
+
case decl
|
|
34
|
+
when ::RBS::AST::Declarations::Base
|
|
35
|
+
decl.comment
|
|
36
|
+
when ::RBS::AST::Ruby::Declarations::Base
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
36
41
|
[entry.decl.comment]
|
|
37
42
|
else
|
|
38
43
|
raise
|
|
@@ -41,11 +46,11 @@ module Steep
|
|
|
41
46
|
|
|
42
47
|
def decl
|
|
43
48
|
case entry = env.constant_entry(full_name)
|
|
44
|
-
when RBS::Environment::ConstantEntry
|
|
49
|
+
when ::RBS::Environment::ConstantEntry
|
|
45
50
|
entry.decl
|
|
46
|
-
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
47
|
-
entry.
|
|
48
|
-
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
51
|
+
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
52
|
+
entry.primary_decl
|
|
53
|
+
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
49
54
|
entry.decl
|
|
50
55
|
else
|
|
51
56
|
raise
|
|
@@ -65,7 +70,12 @@ module Steep
|
|
|
65
70
|
# @implements SimpleMethodNameItem
|
|
66
71
|
|
|
67
72
|
def comment
|
|
68
|
-
method_member
|
|
73
|
+
case method_member
|
|
74
|
+
when ::RBS::AST::Members::Base
|
|
75
|
+
method_member.comment
|
|
76
|
+
when ::RBS::AST::Ruby::Members::Base
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
69
79
|
end
|
|
70
80
|
end
|
|
71
81
|
|
|
@@ -89,18 +99,20 @@ module Steep
|
|
|
89
99
|
|
|
90
100
|
def defining_method_name(type_name, name, member)
|
|
91
101
|
case member
|
|
92
|
-
when RBS::AST::Members::MethodDefinition
|
|
102
|
+
when ::RBS::AST::Members::MethodDefinition
|
|
93
103
|
if member.instance?
|
|
94
104
|
InstanceMethodName.new(type_name: type_name, method_name: name)
|
|
95
105
|
else
|
|
96
106
|
SingletonMethodName.new(type_name: type_name, method_name: name)
|
|
97
107
|
end
|
|
98
|
-
when RBS::AST::Members::Attribute
|
|
108
|
+
when ::RBS::AST::Members::Attribute
|
|
99
109
|
if member.kind == :instance
|
|
100
110
|
InstanceMethodName.new(type_name: type_name, method_name: name)
|
|
101
111
|
else
|
|
102
112
|
SingletonMethodName.new(type_name: type_name, method_name: name)
|
|
103
113
|
end
|
|
114
|
+
when ::RBS::AST::Ruby::Members::DefMember, ::RBS::AST::Ruby::Members::AttributeMember
|
|
115
|
+
InstanceMethodName.new(type_name: type_name, method_name: name)
|
|
104
116
|
end
|
|
105
117
|
end
|
|
106
118
|
end
|
|
@@ -118,9 +130,9 @@ module Steep
|
|
|
118
130
|
env.type_alias_decls.fetch(absolute_type_name).decl
|
|
119
131
|
when absolute_type_name.class?
|
|
120
132
|
case entry = env.module_class_entry(absolute_type_name)
|
|
121
|
-
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
122
|
-
entry.
|
|
123
|
-
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
133
|
+
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
134
|
+
entry.primary_decl
|
|
135
|
+
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
124
136
|
entry.decl
|
|
125
137
|
else
|
|
126
138
|
raise "absolute_type_name=#{absolute_type_name}, relative_type_name=#{relative_type_name}"
|
|
@@ -144,13 +156,18 @@ module Steep
|
|
|
144
156
|
end
|
|
145
157
|
when absolute_type_name.class?
|
|
146
158
|
case entry = env.module_class_entry(absolute_type_name)
|
|
147
|
-
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
148
|
-
entry.
|
|
149
|
-
|
|
150
|
-
|
|
159
|
+
when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
|
|
160
|
+
entry.each_decl do |decl|
|
|
161
|
+
case decl
|
|
162
|
+
when ::RBS::AST::Declarations::Base
|
|
163
|
+
if comment = decl.comment
|
|
164
|
+
comments << comment
|
|
165
|
+
end
|
|
166
|
+
when ::RBS::AST::Ruby::Declarations::Base
|
|
167
|
+
# noop
|
|
151
168
|
end
|
|
152
169
|
end
|
|
153
|
-
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
170
|
+
when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
|
|
154
171
|
if comment = entry.decl.comment
|
|
155
172
|
comments << comment
|
|
156
173
|
end
|
|
@@ -167,646 +184,6 @@ module Steep
|
|
|
167
184
|
|
|
168
185
|
class TextItem < Struct.new(:text, :help_text, :range, :label, keyword_init: true)
|
|
169
186
|
end
|
|
170
|
-
|
|
171
|
-
attr_reader :source_text
|
|
172
|
-
attr_reader :path
|
|
173
|
-
attr_reader :subtyping
|
|
174
|
-
attr_reader :modified_text
|
|
175
|
-
attr_reader :source
|
|
176
|
-
attr_reader :typing
|
|
177
|
-
|
|
178
|
-
def initialize(source_text:, path:, subtyping:)
|
|
179
|
-
@source_text = source_text
|
|
180
|
-
@path = path
|
|
181
|
-
@subtyping = subtyping
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def type_check!(text, line:, column:)
|
|
185
|
-
@modified_text = text
|
|
186
|
-
|
|
187
|
-
Steep.measure "parsing" do
|
|
188
|
-
@source = Source
|
|
189
|
-
.parse(text, path: path, factory: subtyping.factory)
|
|
190
|
-
.without_unrelated_defs(line: line, column: column)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
Steep.measure "typechecking" do
|
|
194
|
-
location = source.buffer.loc_to_pos([line, column])
|
|
195
|
-
resolver = RBS::Resolver::ConstantResolver.new(builder: subtyping.factory.definition_builder)
|
|
196
|
-
@typing = TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver, cursor: location)
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def env
|
|
201
|
-
subtyping.factory.env
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def run(line:, column:)
|
|
205
|
-
source_text = self.source_text.dup
|
|
206
|
-
index = index_for(source_text, line:line, column: column)
|
|
207
|
-
possible_trigger = source_text[index-1]
|
|
208
|
-
|
|
209
|
-
Steep.logger.debug "possible_trigger: #{possible_trigger.inspect}"
|
|
210
|
-
|
|
211
|
-
position = Position.new(line: line, column: column)
|
|
212
|
-
|
|
213
|
-
begin
|
|
214
|
-
Steep.logger.tagged "completion_provider#run(line: #{line}, column: #{column})" do
|
|
215
|
-
Steep.measure "type_check!" do
|
|
216
|
-
type_check!(source_text, line: line, column: column)
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
if comment = at_comment?(position)
|
|
221
|
-
node, *parents = source.find_nodes(line: position.line, column: position.column)
|
|
222
|
-
|
|
223
|
-
case
|
|
224
|
-
when node&.type == :assertion
|
|
225
|
-
# continue
|
|
226
|
-
node or raise
|
|
227
|
-
assertion = node.children[1] #: AST::Node::TypeAssertion
|
|
228
|
-
return items_for_rbs(position: position, buffer: assertion.location.buffer)
|
|
229
|
-
|
|
230
|
-
when node && parents && tapp_node = ([node] + parents).find {|n| n.type == :tapp }
|
|
231
|
-
tapp = tapp_node.children[1] #: AST::Node::TypeApplication
|
|
232
|
-
type_range = tapp.type_location.range
|
|
233
|
-
|
|
234
|
-
if type_range.begin < index && index <= type_range.end
|
|
235
|
-
return items_for_rbs(position: position, buffer: tapp.location.buffer)
|
|
236
|
-
end
|
|
237
|
-
else
|
|
238
|
-
annotation = source.each_annotation.flat_map {|_, annots| annots }.find do |a|
|
|
239
|
-
if a.location
|
|
240
|
-
a.location.start_pos < index && index <= a.location.end_pos
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
if annotation
|
|
245
|
-
annotation.location or raise
|
|
246
|
-
return items_for_rbs(position: position, buffer: annotation.location.buffer)
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
comment_content = comment.text[1..] || ""
|
|
250
|
-
comment_content.strip!
|
|
251
|
-
|
|
252
|
-
range = Range.new(
|
|
253
|
-
start: Position.new(line: line, column: column),
|
|
254
|
-
end: Position.new(line: line, column: column)
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
items = [
|
|
258
|
-
TextItem.new(label: "steep:ignore:start", text: "steep:ignore:start", help_text: "Open ignore block", range: range),
|
|
259
|
-
TextItem.new(label: "steep:ignore:end", text: "steep:ignore:end", help_text: "Close ignore block", range: range),
|
|
260
|
-
TextItem.new(label: "steep:ignore", text: "steep:ignore ${1:optional diagnostics}", help_text: "Ignore line", range: range),
|
|
261
|
-
TextItem.new(label: "@type var x: T", text: "@type var ${1:variable}: ${2:var type}", help_text: "Type of local variable", range: range),
|
|
262
|
-
TextItem.new(label: "@type self: T", text: "@type self: ${1:self type}", help_text: "Type of `self`", range: range),
|
|
263
|
-
TextItem.new(label: "@type block: T", text: "@type block: ${1:block type}", help_text: "Type of `block`", range: range),
|
|
264
|
-
TextItem.new(label: "@type break: T", text: "@type break: ${1:break type}", help_text: "Type of `block`", range: range),
|
|
265
|
-
]
|
|
266
|
-
|
|
267
|
-
items = items.filter_map do |item|
|
|
268
|
-
if item.text.start_with?(comment_content)
|
|
269
|
-
TextItem.new(
|
|
270
|
-
label: item.label,
|
|
271
|
-
text: item.text,
|
|
272
|
-
help_text: item.help_text,
|
|
273
|
-
range: Range.new(
|
|
274
|
-
start: Position.new(line: item.range.start.line, column: item.range.start.column - comment_content.size),
|
|
275
|
-
end: item.range.end
|
|
276
|
-
)
|
|
277
|
-
)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
return items
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
Steep.measure "completion item collection" do
|
|
286
|
-
items_for_trigger(position: position)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
rescue Parser::SyntaxError => exn
|
|
290
|
-
Steep.logger.info "recovering syntax error: #{exn.inspect}"
|
|
291
|
-
|
|
292
|
-
@source_text = source_text.dup
|
|
293
|
-
|
|
294
|
-
case possible_trigger
|
|
295
|
-
when "."
|
|
296
|
-
if source_text[index-2] == "&"
|
|
297
|
-
source_text[index-1] = " "
|
|
298
|
-
source_text[index-2] = " "
|
|
299
|
-
type_check!(source_text, line: line, column: column)
|
|
300
|
-
items_for_qcall(position: position)
|
|
301
|
-
else
|
|
302
|
-
source_text[index-1] = " "
|
|
303
|
-
type_check!(source_text, line: line, column: column)
|
|
304
|
-
items_for_dot(position: position)
|
|
305
|
-
end
|
|
306
|
-
when "@"
|
|
307
|
-
source_text[index-1] = " "
|
|
308
|
-
type_check!(source_text, line: line, column: column)
|
|
309
|
-
items_for_atmark(position: position)
|
|
310
|
-
when ":"
|
|
311
|
-
if source_text[index-2] == ":"
|
|
312
|
-
source_text[index-1] = " "
|
|
313
|
-
source_text[index-2] = " "
|
|
314
|
-
type_check!(source_text, line: line, column: column)
|
|
315
|
-
items_for_colon2(position: position)
|
|
316
|
-
else
|
|
317
|
-
[]
|
|
318
|
-
end
|
|
319
|
-
else
|
|
320
|
-
items = [] #: Array[item]
|
|
321
|
-
items_for_following_keyword_arguments(source_text, index: index, line: line, column: column, items: items)
|
|
322
|
-
items
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
def range_from_loc(loc)
|
|
328
|
-
Range.new(
|
|
329
|
-
start: Position.new(line: loc.line, column: loc.column),
|
|
330
|
-
end: Position.new(line: loc.last_line, column: loc.last_line)
|
|
331
|
-
)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
def at_end?(pos, of:)
|
|
335
|
-
if of
|
|
336
|
-
of.last_line == pos.line && of.last_column == pos.column
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def at_comment?(position)
|
|
341
|
-
source.find_comment(line: position.line, column: position.column)
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def range_for(position, prefix: "")
|
|
345
|
-
if prefix.empty?
|
|
346
|
-
Range.new(start: position, end: position)
|
|
347
|
-
else
|
|
348
|
-
Range.new(start: position - prefix.size, end: position)
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
def items_for_trigger(position:)
|
|
353
|
-
node, *parents = source.find_nodes(line: position.line, column: position.column)
|
|
354
|
-
node ||= source.node
|
|
355
|
-
|
|
356
|
-
return [] unless node && parents
|
|
357
|
-
|
|
358
|
-
items = [] #: Array[item]
|
|
359
|
-
|
|
360
|
-
context = typing.cursor_context.context or raise
|
|
361
|
-
|
|
362
|
-
case
|
|
363
|
-
when node.type == :send && node.children[0] == nil && at_end?(position, of: (_ = node.loc).selector)
|
|
364
|
-
# foo ←
|
|
365
|
-
prefix = node.children[1].to_s
|
|
366
|
-
|
|
367
|
-
method_items_for_receiver_type(context.self_type, include_private: true, prefix: prefix, position: position, items: items)
|
|
368
|
-
local_variable_items_for_context(context, position: position, prefix: prefix, items: items)
|
|
369
|
-
|
|
370
|
-
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*parents))
|
|
371
|
-
keyword_argument_items_for_method(
|
|
372
|
-
call_node: block_node || send_node,
|
|
373
|
-
send_node: send_node,
|
|
374
|
-
position: position,
|
|
375
|
-
prefix: prefix,
|
|
376
|
-
items: items
|
|
377
|
-
)
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
when node.type == :lvar && at_end?(position, of: node.loc)
|
|
381
|
-
# foo ← (lvar)
|
|
382
|
-
local_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
|
383
|
-
|
|
384
|
-
when node.type == :send && node.children[0] && at_end?(position, of: (_ = node.loc).selector)
|
|
385
|
-
# foo.ba ←
|
|
386
|
-
receiver_type =
|
|
387
|
-
case (type = typing.type_of(node: node.children[0]))
|
|
388
|
-
when AST::Types::Self
|
|
389
|
-
context.self_type
|
|
390
|
-
else
|
|
391
|
-
type
|
|
392
|
-
end
|
|
393
|
-
prefix = node.children[1].to_s
|
|
394
|
-
|
|
395
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: prefix, position: position, items: items)
|
|
396
|
-
|
|
397
|
-
when node.type == :csend && node.children[0] && at_end?(position, of: (_ = node.loc).selector)
|
|
398
|
-
# foo&.ba ←
|
|
399
|
-
receiver_type =
|
|
400
|
-
case (type = typing.type_of(node: node.children[0]))
|
|
401
|
-
when AST::Types::Self
|
|
402
|
-
context.self_type
|
|
403
|
-
else
|
|
404
|
-
unwrap_optional(type)
|
|
405
|
-
end
|
|
406
|
-
prefix = node.children[1].to_s
|
|
407
|
-
|
|
408
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: prefix, position: position, items: items)
|
|
409
|
-
|
|
410
|
-
when node.type == :const && node.children[0] == nil && at_end?(position, of: node.loc)
|
|
411
|
-
# Foo ← (const)
|
|
412
|
-
prefix = node.children[1].to_s
|
|
413
|
-
|
|
414
|
-
method_items_for_receiver_type(context.self_type, include_private: false, prefix: prefix, position: position, items: items)
|
|
415
|
-
constant_items_for_context(context, prefix: prefix, position: position, items: items)
|
|
416
|
-
|
|
417
|
-
when node.type == :const && node.children[0] && at_end?(position, of: node.loc)
|
|
418
|
-
# Foo::Ba ← (const)
|
|
419
|
-
parent_node = node.children[0]
|
|
420
|
-
parent_type = typing.type_of(node: parent_node)
|
|
421
|
-
|
|
422
|
-
if parent_type
|
|
423
|
-
prefix = node.children[1].to_s
|
|
424
|
-
|
|
425
|
-
method_items_for_receiver_type(parent_type, include_private: false, prefix: prefix, position: position, items: items)
|
|
426
|
-
constant_items_for_context(context, parent: parent_node, prefix: prefix, position: position, items: items)
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
when node.type == :send && at_end?(position, of: (_ = node.loc).dot) && (_ = node.loc).dot.source == "."
|
|
430
|
-
# foo.← ba
|
|
431
|
-
receiver_type =
|
|
432
|
-
case (type = typing.type_of(node: node.children[0]))
|
|
433
|
-
when AST::Types::Self
|
|
434
|
-
context.self_type
|
|
435
|
-
else
|
|
436
|
-
type
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: "", position: position, items: items)
|
|
440
|
-
|
|
441
|
-
when node.type == :send && at_end?(position, of: (_ = node.loc).dot) && (_ = node.loc).dot.source == "::"
|
|
442
|
-
# foo::← ba
|
|
443
|
-
items.push(*items_for_colon2(position: position))
|
|
444
|
-
|
|
445
|
-
when node.type == :csend && at_end?(position, of: (_ = node.loc).dot)
|
|
446
|
-
# foo&.← ba
|
|
447
|
-
receiver_type =
|
|
448
|
-
case (type = typing.type_of(node: node.children[0]))
|
|
449
|
-
when AST::Types::Self
|
|
450
|
-
context.self_type
|
|
451
|
-
else
|
|
452
|
-
unwrap_optional(type)
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: "", position: position, items: items)
|
|
456
|
-
|
|
457
|
-
when node.type == :ivar && at_end?(position, of: node.loc)
|
|
458
|
-
# @fo ←
|
|
459
|
-
instance_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
|
460
|
-
|
|
461
|
-
else
|
|
462
|
-
method_items_for_receiver_type(context.self_type, include_private: true, prefix: "", position: position, items: items)
|
|
463
|
-
local_variable_items_for_context(context, position: position, prefix: "", items: items)
|
|
464
|
-
instance_variable_items_for_context(context, position: position, prefix: "", items: items)
|
|
465
|
-
constant_items_for_context(context, position: position, prefix: "", items: items)
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
items
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
def items_for_dot(position:)
|
|
472
|
-
# foo. ←
|
|
473
|
-
shift_pos = position-1
|
|
474
|
-
node, *_parents = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
|
475
|
-
node ||= source.node
|
|
476
|
-
|
|
477
|
-
return [] unless node
|
|
478
|
-
|
|
479
|
-
if at_end?(shift_pos, of: node.loc)
|
|
480
|
-
begin
|
|
481
|
-
context = typing.cursor_context.context or raise
|
|
482
|
-
receiver_type =
|
|
483
|
-
case (type = typing.type_of(node: node))
|
|
484
|
-
when AST::Types::Self
|
|
485
|
-
context.self_type
|
|
486
|
-
else
|
|
487
|
-
type
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
items = [] #: Array[item]
|
|
491
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: "", position: position, items: items)
|
|
492
|
-
items
|
|
493
|
-
rescue Typing::UnknownNodeError
|
|
494
|
-
[]
|
|
495
|
-
end
|
|
496
|
-
else
|
|
497
|
-
[]
|
|
498
|
-
end
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
def items_for_qcall(position:)
|
|
502
|
-
# foo&. ←
|
|
503
|
-
shift_pos = position-2
|
|
504
|
-
node, *_parents = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
|
505
|
-
node ||= source.node
|
|
506
|
-
|
|
507
|
-
return [] unless node
|
|
508
|
-
|
|
509
|
-
if at_end?(shift_pos, of: node.loc)
|
|
510
|
-
begin
|
|
511
|
-
context = typing.cursor_context.context or raise
|
|
512
|
-
receiver_type =
|
|
513
|
-
case (type = typing.type_of(node: node))
|
|
514
|
-
when AST::Types::Self
|
|
515
|
-
context.self_type
|
|
516
|
-
else
|
|
517
|
-
unwrap_optional(type)
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
items = [] #: Array[item]
|
|
521
|
-
method_items_for_receiver_type(receiver_type, include_private: false, prefix: "", position: position, items: items)
|
|
522
|
-
items
|
|
523
|
-
rescue Typing::UnknownNodeError
|
|
524
|
-
[]
|
|
525
|
-
end
|
|
526
|
-
else
|
|
527
|
-
[]
|
|
528
|
-
end
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
def items_for_colon2(position:)
|
|
532
|
-
# :: ←
|
|
533
|
-
shift_pos = position-2
|
|
534
|
-
node, *_ = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
|
535
|
-
node ||= source.node
|
|
536
|
-
|
|
537
|
-
items = [] #: Array[item]
|
|
538
|
-
case node&.type
|
|
539
|
-
when :const
|
|
540
|
-
# Constant:: ←
|
|
541
|
-
context = typing.cursor_context.context or raise
|
|
542
|
-
constant_items_for_context(context, parent: node, position: position, items: items, prefix: "")
|
|
543
|
-
when nil
|
|
544
|
-
# :: ←
|
|
545
|
-
context = typing.cursor_context.context or raise
|
|
546
|
-
constant_items_for_context(context, parent: nil, position: position, items: items, prefix: "")
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
if node
|
|
550
|
-
items.push(*items_for_dot(position: position - 1))
|
|
551
|
-
end
|
|
552
|
-
|
|
553
|
-
items
|
|
554
|
-
end
|
|
555
|
-
|
|
556
|
-
def items_for_atmark(position:)
|
|
557
|
-
# @ ←
|
|
558
|
-
shift_pos = position-1
|
|
559
|
-
node, *_ = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
|
560
|
-
node ||= source.node
|
|
561
|
-
|
|
562
|
-
return [] unless node
|
|
563
|
-
|
|
564
|
-
context = typing.cursor_context.context or raise
|
|
565
|
-
items = [] #: Array[item]
|
|
566
|
-
instance_variable_items_for_context(context, prefix: "@", position: position, items: items)
|
|
567
|
-
items
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
def items_for_rbs(position:, buffer:)
|
|
571
|
-
items = [] #: Array[item]
|
|
572
|
-
|
|
573
|
-
context = typing.cursor_context.context or raise
|
|
574
|
-
completion = TypeNameCompletion.new(env: context.env, context: context.module_context.nesting, dirs: [])
|
|
575
|
-
prefix = TypeNameCompletion::Prefix.parse(buffer, line: position.line, column: position.column)
|
|
576
|
-
|
|
577
|
-
size = prefix&.size || 0
|
|
578
|
-
range = Range.new(start: position - size, end: position)
|
|
579
|
-
|
|
580
|
-
completion.find_type_names(prefix).each do |name|
|
|
581
|
-
absolute, relative = completion.resolve_name_in_context(name)
|
|
582
|
-
items << TypeNameItem.new(relative_type_name: relative, absolute_type_name: absolute, env: context.env, range: range)
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
items
|
|
586
|
-
end
|
|
587
|
-
|
|
588
|
-
def items_for_following_keyword_arguments(text, index:, line:, column:, items:)
|
|
589
|
-
return if text[index - 1] !~ /[a-zA-Z0-9]/
|
|
590
|
-
|
|
591
|
-
text = text.dup
|
|
592
|
-
argname = [] #: Array[String]
|
|
593
|
-
while text[index - 1] =~ /[a-zA-Z0-9]/
|
|
594
|
-
argname.unshift(text[index - 1] || '')
|
|
595
|
-
source_text[index - 1] = " "
|
|
596
|
-
index -= 1
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
begin
|
|
600
|
-
type_check!(source_text, line: line, column: column)
|
|
601
|
-
rescue Parser::SyntaxError
|
|
602
|
-
return
|
|
603
|
-
end
|
|
604
|
-
|
|
605
|
-
if nodes = source.find_nodes(line: line, column: column)
|
|
606
|
-
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*nodes))
|
|
607
|
-
position = Position.new(line: line, column: column)
|
|
608
|
-
keyword_argument_items_for_method(
|
|
609
|
-
call_node: block_node || send_node,
|
|
610
|
-
send_node: send_node,
|
|
611
|
-
position: position,
|
|
612
|
-
prefix: argname.join,
|
|
613
|
-
items: items
|
|
614
|
-
)
|
|
615
|
-
end
|
|
616
|
-
end
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
def method_items_for_receiver_type(type, include_private:, prefix:, position:, items:)
|
|
620
|
-
range = range_for(position, prefix: prefix)
|
|
621
|
-
context = typing.cursor_context.context or raise
|
|
622
|
-
|
|
623
|
-
config =
|
|
624
|
-
if (module_type = context.module_context&.module_type) && (instance_type = context.module_context&.instance_type)
|
|
625
|
-
Interface::Builder::Config.new(
|
|
626
|
-
self_type: context.self_type,
|
|
627
|
-
class_type: module_type,
|
|
628
|
-
instance_type: instance_type,
|
|
629
|
-
variable_bounds: context.variable_context.upper_bounds
|
|
630
|
-
)
|
|
631
|
-
else
|
|
632
|
-
Interface::Builder::Config.new(self_type: context.self_type, variable_bounds: context.variable_context.upper_bounds)
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
if shape = subtyping.builder.shape(type, config)
|
|
636
|
-
shape = shape.public_shape unless include_private
|
|
637
|
-
|
|
638
|
-
shape.methods.each do |name, method_entry|
|
|
639
|
-
next if disallowed_method?(name)
|
|
640
|
-
|
|
641
|
-
if name.to_s.start_with?(prefix)
|
|
642
|
-
if word_name?(name.to_s)
|
|
643
|
-
case type
|
|
644
|
-
when AST::Types::Name::Instance, AST::Types::Name::Interface, AST::Types::Name::Singleton
|
|
645
|
-
# Simple method type
|
|
646
|
-
all_decls = Set.new(method_entry.overloads.flat_map {|overload| overload.method_decls(name) }).sort_by {|decl| decl.method_name.to_s }
|
|
647
|
-
all_members = Set.new(all_decls.flat_map {|decl| decl.method_def.member })
|
|
648
|
-
all_members.each do |member|
|
|
649
|
-
associated_decl = all_decls.find {|decl| decl.method_def.member == member } or next
|
|
650
|
-
overloads = method_entry.overloads.select {|overload| overload.method_defs.any? {|defn| defn.member == member }}
|
|
651
|
-
annotations = associated_decl.method_def.member_annotations
|
|
652
|
-
items << SimpleMethodNameItem.new(
|
|
653
|
-
identifier: name,
|
|
654
|
-
range: range,
|
|
655
|
-
receiver_type: type,
|
|
656
|
-
method_name: associated_decl.method_name,
|
|
657
|
-
method_types: overloads.map {|overload| subtyping.factory.method_type_1(overload.method_type) },
|
|
658
|
-
method_member: member,
|
|
659
|
-
deprecated: AnnotationsHelper.deprecated_annotation?(annotations) ? true : false
|
|
660
|
-
)
|
|
661
|
-
end
|
|
662
|
-
else
|
|
663
|
-
generated_overloads, defined_overloads =
|
|
664
|
-
method_entry.overloads.partition {|overload| overload.method_defs.empty? }
|
|
665
|
-
|
|
666
|
-
unless defined_overloads.empty?
|
|
667
|
-
items << ComplexMethodNameItem.new(
|
|
668
|
-
identifier: name,
|
|
669
|
-
range: range,
|
|
670
|
-
receiver_type: type,
|
|
671
|
-
method_types: defined_overloads.map { subtyping.factory.method_type_1(_1.method_type) },
|
|
672
|
-
method_decls: defined_overloads.flat_map { _1.method_decls(name).to_a }.sort_by {|decl| decl.method_name.to_s }
|
|
673
|
-
)
|
|
674
|
-
end
|
|
675
|
-
|
|
676
|
-
unless generated_overloads.empty?
|
|
677
|
-
items << GeneratedMethodNameItem.new(
|
|
678
|
-
identifier: name,
|
|
679
|
-
range: range,
|
|
680
|
-
receiver_type: type,
|
|
681
|
-
method_types: generated_overloads.map { subtyping.factory.method_type_1(_1.method_type) }
|
|
682
|
-
)
|
|
683
|
-
end
|
|
684
|
-
end
|
|
685
|
-
end
|
|
686
|
-
end
|
|
687
|
-
end
|
|
688
|
-
end
|
|
689
|
-
end
|
|
690
|
-
|
|
691
|
-
def word_name?(name)
|
|
692
|
-
name =~ /\w/ ? true : false
|
|
693
|
-
end
|
|
694
|
-
|
|
695
|
-
def local_variable_items_for_context(context, position:, prefix:, items:)
|
|
696
|
-
range = range_for(position, prefix: prefix)
|
|
697
|
-
context.type_env.local_variable_types.each do |name, pair|
|
|
698
|
-
type, _ = pair
|
|
699
|
-
|
|
700
|
-
if name.to_s.start_with?(prefix)
|
|
701
|
-
items << LocalVariableItem.new(identifier: name, range: range, type: type)
|
|
702
|
-
end
|
|
703
|
-
end
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
def constant_items_for_context(context, parent: nil, position:, prefix:, items:)
|
|
707
|
-
range = range_for(position, prefix: prefix)
|
|
708
|
-
|
|
709
|
-
if parent
|
|
710
|
-
case parent.type
|
|
711
|
-
when :const
|
|
712
|
-
const_name = typing.source_index.reference(constant_node: parent) or raise "Unknown node in source_index: #{parent}"
|
|
713
|
-
consts = context.type_env.constant_env.children(const_name)
|
|
714
|
-
end
|
|
715
|
-
else
|
|
716
|
-
consts = context.type_env.constant_env.constants
|
|
717
|
-
end
|
|
718
|
-
|
|
719
|
-
if consts
|
|
720
|
-
consts.each do |name, tuple|
|
|
721
|
-
type, full_name, _ = tuple
|
|
722
|
-
|
|
723
|
-
if name.to_s.start_with?(prefix)
|
|
724
|
-
items << ConstantItem.new(env: env, identifier: name, range: range, type: type, full_name: full_name)
|
|
725
|
-
end
|
|
726
|
-
end
|
|
727
|
-
end
|
|
728
|
-
end
|
|
729
|
-
|
|
730
|
-
def instance_variable_items_for_context(context, position:, prefix:, items:)
|
|
731
|
-
range = range_for(position, prefix: prefix)
|
|
732
|
-
context.type_env.instance_variable_types.each do |name, type|
|
|
733
|
-
if name.to_s.start_with?(prefix)
|
|
734
|
-
items << InstanceVariableItem.new(identifier: name, range: range, type: type)
|
|
735
|
-
end
|
|
736
|
-
end
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
def keyword_argument_items_for_method(call_node:, send_node:, position:, prefix:, items:)
|
|
740
|
-
_receiver_node, _method_name, argument_nodes = deconstruct_send_node!(send_node)
|
|
741
|
-
|
|
742
|
-
call = typing.call_of(node: call_node)
|
|
743
|
-
|
|
744
|
-
case call
|
|
745
|
-
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
|
746
|
-
context = typing.cursor_context.context or raise
|
|
747
|
-
type = call.receiver_type
|
|
748
|
-
type = type.subst(Interface::Substitution.build([], self_type: context.self_type, module_type: context.module_context&.module_type, instance_type: context.module_context&.instance_type))
|
|
749
|
-
|
|
750
|
-
config = Interface::Builder::Config.new(self_type: type, variable_bounds: context.variable_context.upper_bounds)
|
|
751
|
-
if shape = subtyping.builder.shape(type, config)
|
|
752
|
-
shape = shape.public_shape if private_send?(call_node)
|
|
753
|
-
if method = shape.methods[call.method_name]
|
|
754
|
-
method.overloads.each.with_index do |overload, i|
|
|
755
|
-
defn = overload.method_decls(call.method_name).to_a[0]&.method_def
|
|
756
|
-
if defn && defn.type.type
|
|
757
|
-
range = range_for(position, prefix: prefix)
|
|
758
|
-
kwargs = argument_nodes.find { |arg| arg.type == :kwargs }&.children || []
|
|
759
|
-
used_kwargs = kwargs.filter_map { |arg| arg.type == :pair && arg.children.first.children.first }
|
|
760
|
-
|
|
761
|
-
if defn.type.type.is_a?(RBS::Types::UntypedFunction)
|
|
762
|
-
kwargs = [] #: Array[Symbol]
|
|
763
|
-
else
|
|
764
|
-
kwargs = defn.type.type.required_keywords.keys + defn.type.type.optional_keywords.keys
|
|
765
|
-
end
|
|
766
|
-
|
|
767
|
-
kwargs.each do |name|
|
|
768
|
-
if name.to_s.start_with?(prefix) && !used_kwargs.include?(name)
|
|
769
|
-
items << KeywordArgumentItem.new(identifier: "#{name}:", range: range)
|
|
770
|
-
end
|
|
771
|
-
end
|
|
772
|
-
end
|
|
773
|
-
end
|
|
774
|
-
end
|
|
775
|
-
end
|
|
776
|
-
end
|
|
777
|
-
end
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
def index_for(string, line:, column:)
|
|
781
|
-
index = 0
|
|
782
|
-
|
|
783
|
-
string.each_line.with_index do |s, i|
|
|
784
|
-
if i+1 == line
|
|
785
|
-
index += column
|
|
786
|
-
break
|
|
787
|
-
else
|
|
788
|
-
index += s.size
|
|
789
|
-
end
|
|
790
|
-
end
|
|
791
|
-
|
|
792
|
-
index
|
|
793
|
-
end
|
|
794
|
-
|
|
795
|
-
def disallowed_method?(name)
|
|
796
|
-
# initialize isn't invoked by developers when creating
|
|
797
|
-
# instances of new classes, so don't show it as
|
|
798
|
-
# an LSP option
|
|
799
|
-
name == :initialize
|
|
800
|
-
end
|
|
801
|
-
|
|
802
|
-
def unwrap_optional(type)
|
|
803
|
-
if type.is_a?(AST::Types::Union) && type.types.include?(AST::Builtin.nil_type)
|
|
804
|
-
types = type.types.reject { |t| t == AST::Builtin.nil_type }
|
|
805
|
-
AST::Types::Union.new(types: types)
|
|
806
|
-
else
|
|
807
|
-
type
|
|
808
|
-
end
|
|
809
|
-
end
|
|
810
187
|
end
|
|
811
188
|
end
|
|
812
189
|
end
|