steep-relaxed 1.9.3.3

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