steep-activesupport-4 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) 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/Steepfile +68 -0
  9. data/bin/console +14 -0
  10. data/bin/generate-diagnostics-docs.rb +112 -0
  11. data/bin/mem_graph.rb +67 -0
  12. data/bin/mem_prof.rb +102 -0
  13. data/bin/output_rebaseline.rb +34 -0
  14. data/bin/output_test.rb +60 -0
  15. data/bin/rbs +20 -0
  16. data/bin/rbs-inline +19 -0
  17. data/bin/setup +9 -0
  18. data/bin/stackprof_test.rb +19 -0
  19. data/bin/steep +19 -0
  20. data/bin/steep-check.rb +251 -0
  21. data/bin/steep-prof +16 -0
  22. data/doc/narrowing.md +195 -0
  23. data/doc/shape.md +194 -0
  24. data/exe/steep +18 -0
  25. data/guides/README.md +5 -0
  26. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
  27. data/guides/src/getting-started/getting-started.md +163 -0
  28. data/guides/src/nil-optional/nil-optional.md +195 -0
  29. data/lib/steep/annotation_parser.rb +199 -0
  30. data/lib/steep/ast/annotation/collection.rb +172 -0
  31. data/lib/steep/ast/annotation.rb +137 -0
  32. data/lib/steep/ast/builtin.rb +104 -0
  33. data/lib/steep/ast/ignore.rb +148 -0
  34. data/lib/steep/ast/node/type_application.rb +88 -0
  35. data/lib/steep/ast/node/type_assertion.rb +81 -0
  36. data/lib/steep/ast/types/any.rb +35 -0
  37. data/lib/steep/ast/types/boolean.rb +45 -0
  38. data/lib/steep/ast/types/bot.rb +35 -0
  39. data/lib/steep/ast/types/class.rb +43 -0
  40. data/lib/steep/ast/types/factory.rb +557 -0
  41. data/lib/steep/ast/types/helper.rb +40 -0
  42. data/lib/steep/ast/types/instance.rb +42 -0
  43. data/lib/steep/ast/types/intersection.rb +93 -0
  44. data/lib/steep/ast/types/literal.rb +59 -0
  45. data/lib/steep/ast/types/logic.rb +84 -0
  46. data/lib/steep/ast/types/name.rb +128 -0
  47. data/lib/steep/ast/types/nil.rb +41 -0
  48. data/lib/steep/ast/types/proc.rb +117 -0
  49. data/lib/steep/ast/types/record.rb +79 -0
  50. data/lib/steep/ast/types/self.rb +43 -0
  51. data/lib/steep/ast/types/shared_instance.rb +11 -0
  52. data/lib/steep/ast/types/top.rb +35 -0
  53. data/lib/steep/ast/types/tuple.rb +60 -0
  54. data/lib/steep/ast/types/union.rb +97 -0
  55. data/lib/steep/ast/types/var.rb +65 -0
  56. data/lib/steep/ast/types/void.rb +35 -0
  57. data/lib/steep/cli.rb +401 -0
  58. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  59. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  60. data/lib/steep/diagnostic/helper.rb +18 -0
  61. data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
  62. data/lib/steep/diagnostic/result_printer2.rb +48 -0
  63. data/lib/steep/diagnostic/ruby.rb +1221 -0
  64. data/lib/steep/diagnostic/signature.rb +570 -0
  65. data/lib/steep/drivers/annotations.rb +52 -0
  66. data/lib/steep/drivers/check.rb +339 -0
  67. data/lib/steep/drivers/checkfile.rb +210 -0
  68. data/lib/steep/drivers/diagnostic_printer.rb +105 -0
  69. data/lib/steep/drivers/init.rb +66 -0
  70. data/lib/steep/drivers/langserver.rb +56 -0
  71. data/lib/steep/drivers/print_project.rb +113 -0
  72. data/lib/steep/drivers/stats.rb +203 -0
  73. data/lib/steep/drivers/utils/driver_helper.rb +143 -0
  74. data/lib/steep/drivers/utils/jobs_option.rb +26 -0
  75. data/lib/steep/drivers/vendor.rb +27 -0
  76. data/lib/steep/drivers/watch.rb +194 -0
  77. data/lib/steep/drivers/worker.rb +58 -0
  78. data/lib/steep/equatable.rb +23 -0
  79. data/lib/steep/expectations.rb +228 -0
  80. data/lib/steep/index/rbs_index.rb +350 -0
  81. data/lib/steep/index/signature_symbol_provider.rb +185 -0
  82. data/lib/steep/index/source_index.rb +167 -0
  83. data/lib/steep/interface/block.rb +103 -0
  84. data/lib/steep/interface/builder.rb +843 -0
  85. data/lib/steep/interface/function.rb +1090 -0
  86. data/lib/steep/interface/method_type.rb +330 -0
  87. data/lib/steep/interface/shape.rb +239 -0
  88. data/lib/steep/interface/substitution.rb +159 -0
  89. data/lib/steep/interface/type_param.rb +115 -0
  90. data/lib/steep/located_value.rb +20 -0
  91. data/lib/steep/method_name.rb +42 -0
  92. data/lib/steep/module_helper.rb +24 -0
  93. data/lib/steep/node_helper.rb +273 -0
  94. data/lib/steep/path_helper.rb +30 -0
  95. data/lib/steep/project/dsl.rb +268 -0
  96. data/lib/steep/project/group.rb +31 -0
  97. data/lib/steep/project/options.rb +63 -0
  98. data/lib/steep/project/pattern.rb +59 -0
  99. data/lib/steep/project/target.rb +92 -0
  100. data/lib/steep/project.rb +78 -0
  101. data/lib/steep/rake_task.rb +132 -0
  102. data/lib/steep/range_extension.rb +29 -0
  103. data/lib/steep/server/base_worker.rb +97 -0
  104. data/lib/steep/server/change_buffer.rb +73 -0
  105. data/lib/steep/server/custom_methods.rb +77 -0
  106. data/lib/steep/server/delay_queue.rb +45 -0
  107. data/lib/steep/server/interaction_worker.rb +492 -0
  108. data/lib/steep/server/lsp_formatter.rb +455 -0
  109. data/lib/steep/server/master.rb +912 -0
  110. data/lib/steep/server/target_group_files.rb +205 -0
  111. data/lib/steep/server/type_check_controller.rb +366 -0
  112. data/lib/steep/server/type_check_worker.rb +303 -0
  113. data/lib/steep/server/work_done_progress.rb +64 -0
  114. data/lib/steep/server/worker_process.rb +176 -0
  115. data/lib/steep/services/completion_provider.rb +802 -0
  116. data/lib/steep/services/content_change.rb +61 -0
  117. data/lib/steep/services/file_loader.rb +74 -0
  118. data/lib/steep/services/goto_service.rb +441 -0
  119. data/lib/steep/services/hover_provider/rbs.rb +88 -0
  120. data/lib/steep/services/hover_provider/ruby.rb +221 -0
  121. data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
  122. data/lib/steep/services/path_assignment.rb +46 -0
  123. data/lib/steep/services/signature_help_provider.rb +202 -0
  124. data/lib/steep/services/signature_service.rb +428 -0
  125. data/lib/steep/services/stats_calculator.rb +68 -0
  126. data/lib/steep/services/type_check_service.rb +394 -0
  127. data/lib/steep/services/type_name_completion.rb +236 -0
  128. data/lib/steep/signature/validator.rb +651 -0
  129. data/lib/steep/source/ignore_ranges.rb +69 -0
  130. data/lib/steep/source.rb +691 -0
  131. data/lib/steep/subtyping/cache.rb +30 -0
  132. data/lib/steep/subtyping/check.rb +1113 -0
  133. data/lib/steep/subtyping/constraints.rb +341 -0
  134. data/lib/steep/subtyping/relation.rb +101 -0
  135. data/lib/steep/subtyping/result.rb +324 -0
  136. data/lib/steep/subtyping/variable_variance.rb +89 -0
  137. data/lib/steep/test.rb +9 -0
  138. data/lib/steep/thread_waiter.rb +43 -0
  139. data/lib/steep/type_construction.rb +5183 -0
  140. data/lib/steep/type_inference/block_params.rb +416 -0
  141. data/lib/steep/type_inference/case_when.rb +303 -0
  142. data/lib/steep/type_inference/constant_env.rb +56 -0
  143. data/lib/steep/type_inference/context.rb +195 -0
  144. data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
  145. data/lib/steep/type_inference/method_call.rb +193 -0
  146. data/lib/steep/type_inference/method_params.rb +531 -0
  147. data/lib/steep/type_inference/multiple_assignment.rb +194 -0
  148. data/lib/steep/type_inference/send_args.rb +712 -0
  149. data/lib/steep/type_inference/type_env.rb +341 -0
  150. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  151. data/lib/steep/typing.rb +321 -0
  152. data/lib/steep/version.rb +3 -0
  153. data/lib/steep.rb +369 -0
  154. data/manual/annotations.md +181 -0
  155. data/manual/ignore.md +20 -0
  156. data/manual/ruby-diagnostics.md +1879 -0
  157. data/sample/Steepfile +22 -0
  158. data/sample/lib/conference.rb +49 -0
  159. data/sample/lib/length.rb +35 -0
  160. data/sample/sig/conference.rbs +42 -0
  161. data/sample/sig/generics.rbs +15 -0
  162. data/sample/sig/length.rbs +34 -0
  163. data/steep-activesupport-4.gemspec +55 -0
  164. metadata +437 -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