steep 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e95857ced793435c07c948b2a51ac914c52816811ae8e5d18337bcf946eb33d
4
- data.tar.gz: 9038e63999222be3e0b7172aa423056ef7792b905e1d277271fa795b6ca06889
3
+ metadata.gz: 86924db409406024edb29a087196304bacba8730dfa3c986c604fbe8b6b9a6fd
4
+ data.tar.gz: d688f6b2f58343da51328f13bc26da7e4e54de7f1dd9393f0cd98d48c5ea8420
5
5
  SHA512:
6
- metadata.gz: 2747b3e5f3303ae48a91e76b2256cd1e402e7022caa714083267da0820f1bce2d81188586e551a10158d4c6716ab7a8db8562aa84b31c98731872b08d05048c9
7
- data.tar.gz: 9d5bd44685d8228ee304bdaf94ae52e5eef2a2871580e7190ef941ea510406eab28bdb3aa6849fd9234649da10cd9344e2c38ba309a11a73cca70c6ed7e946e3
6
+ metadata.gz: a70b109afc79267f2a47425dcc8b93f05074fbffa1e410fa62824b5a94320f18a9274182ad2fbaa4083867dd0bab9e4e8796fc8b472edd2328d2b332e76f9f66
7
+ data.tar.gz: 6b4dc08b74b0f042b325180f1b358862d510fefe06a9e07f06380bbf7e86f47e3547d365d0cc94a278c80946befec64689a5c56e87a3e820db767103727e69f7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.14.0 (2020-02-24)
6
+
7
+ * Implementat LSP _completion_. ([#119](https://github.com/soutaro/steep/pull/119))
8
+ * Update ruby-signature. ([#120](https://github.com/soutaro/steep/pull/120))
9
+ * Rescue errors during `langserver`. ([#121](https://github.com/soutaro/steep/pull/121))
10
+ * Pass hint when type checking `return`. ([#122](https://github.com/soutaro/steep/pull/122))
11
+ * Remove trailing spaces from Steepfile. ([#118](https://github.com/soutaro/steep/pull/118))
12
+
5
13
  ## 0.13.0 (2020-02-16)
6
14
 
7
15
  * Improve LSP _hover_ support. ([#117](https://github.com/soutaro/steep/pull/117))
data/lib/steep.rb CHANGED
@@ -74,6 +74,7 @@ require "steep/project/target"
74
74
  require "steep/project/dsl"
75
75
  require "steep/project/file_loader"
76
76
  require "steep/project/hover_content"
77
+ require "steep/project/completion_provider"
77
78
  require "steep/drivers/utils/driver_helper"
78
79
  require "steep/drivers/check"
79
80
  require "steep/drivers/validate"
@@ -114,4 +115,19 @@ module Steep
114
115
 
115
116
  @logger = nil
116
117
  self.log_output = STDERR
118
+
119
+ def self.measure(message)
120
+ start = Time.now
121
+ yield.tap do
122
+ time = Time.now - start
123
+ self.logger.info "#{message} took #{time} seconds"
124
+ end
125
+ end
126
+
127
+ def self.log_error(exn, message: "Unexpected error: #{exn.inspect}")
128
+ Steep.logger.error message
129
+ exn.backtrace.each do |loc|
130
+ Steep.logger.warn " #{loc}"
131
+ end
132
+ end
117
133
  end
@@ -187,47 +187,82 @@ module Steep
187
187
  end
188
188
 
189
189
  def method_type(method_type, self_type:)
190
- case method_type
191
- when Ruby::Signature::MethodType
192
- fvs = self_type.free_variables()
193
-
194
- type_params = []
195
- alpha_vars = []
196
- alpha_types = []
197
-
198
- method_type.type_params.map do |name|
199
- if fvs.include?(name)
200
- type = Types::Var.fresh(name)
201
- alpha_vars << name
202
- alpha_types << type
203
- type_params << type.name
204
- else
205
- type_params << name
206
- end
190
+ fvs = self_type.free_variables()
191
+
192
+ type_params = []
193
+ alpha_vars = []
194
+ alpha_types = []
195
+
196
+ method_type.type_params.map do |name|
197
+ if fvs.include?(name)
198
+ type = Types::Var.fresh(name)
199
+ alpha_vars << name
200
+ alpha_types << type
201
+ type_params << type.name
202
+ else
203
+ type_params << name
207
204
  end
208
- subst = Interface::Substitution.build(alpha_vars, alpha_types)
209
-
210
- type = Interface::MethodType.new(
211
- type_params: type_params,
212
- return_type: type(method_type.type.return_type).subst(subst),
213
- params: params(method_type.type).subst(subst),
214
- location: nil,
215
- block: method_type.block&.yield_self do |block|
216
- Interface::Block.new(
217
- optional: !block.required,
218
- type: Proc.new(params: params(block.type).subst(subst),
219
- return_type: type(block.type.return_type).subst(subst), location: nil)
220
- )
221
- end
222
- )
205
+ end
206
+ subst = Interface::Substitution.build(alpha_vars, alpha_types)
207
+
208
+ type = Interface::MethodType.new(
209
+ type_params: type_params,
210
+ return_type: type(method_type.type.return_type).subst(subst),
211
+ params: params(method_type.type).subst(subst),
212
+ location: nil,
213
+ block: method_type.block&.yield_self do |block|
214
+ Interface::Block.new(
215
+ optional: !block.required,
216
+ type: Proc.new(params: params(block.type).subst(subst),
217
+ return_type: type(block.type.return_type).subst(subst), location: nil)
218
+ )
219
+ end
220
+ )
221
+
222
+ if block_given?
223
+ yield type
224
+ else
225
+ type
226
+ end
227
+ end
228
+
229
+ def method_type_1(method_type, self_type:)
230
+ fvs = self_type.free_variables()
223
231
 
224
- if block_given?
225
- yield type
232
+ type_params = []
233
+ alpha_vars = []
234
+ alpha_types = []
235
+
236
+ method_type.type_params.map do |name|
237
+ if fvs.include?(name)
238
+ type = Ruby::Signature::Types::Variable.new(name: name, location: nil),
239
+ alpha_vars << name
240
+ alpha_types << type
241
+ type_params << type.name
226
242
  else
227
- type
243
+ type_params << name
228
244
  end
229
- when :any
230
- :any
245
+ end
246
+ subst = Interface::Substitution.build(alpha_vars, alpha_types)
247
+
248
+ type = Ruby::Signature::MethodType.new(
249
+ type_params: type_params,
250
+ type: function_1(method_type.params.subst(subst), method_type.return_type.subst(subst)),
251
+ block: method_type.block&.yield_self do |block|
252
+ block_type = block.type.subst(subst)
253
+
254
+ Ruby::Signature::MethodType::Block.new(
255
+ type: function_1(block_type.params, block_type.return_type),
256
+ required: !block.optional
257
+ )
258
+ end,
259
+ location: nil
260
+ )
261
+
262
+ if block_given?
263
+ yield type
264
+ else
265
+ type
231
266
  end
232
267
  end
233
268
 
@@ -10,21 +10,21 @@ module Steep
10
10
  TEMPLATE = <<~EOF
11
11
  # target :lib do
12
12
  # signature "sig"
13
- #
13
+ #
14
14
  # check "lib" # Directory name
15
15
  # check "Gemfile" # File name
16
16
  # check "app/models/**/*.rb" # Glob
17
- # # ignore "lib/templates/*.rb"
18
- #
17
+ # # ignore "lib/templates/*.rb"
18
+ #
19
19
  # # library "pathname", "set" # Standard libraries
20
20
  # # library "strong_json" # Gems
21
21
  # end
22
22
 
23
23
  # target :spec do
24
24
  # signature "sig", "sig-private"
25
- #
25
+ #
26
26
  # check "spec"
27
- #
27
+ #
28
28
  # # library "pathname", "set" # Standard libraries
29
29
  # # library "rspec"
30
30
  # end
@@ -84,10 +84,55 @@ module Steep
84
84
  change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::FULL
85
85
  ),
86
86
  hover_provider: true,
87
+ completion_provider: LanguageServer::Protocol::Interface::CompletionOptions.new(
88
+ trigger_characters: [".", "@"],
87
89
  )
90
+ )
88
91
  )
89
92
 
90
93
  enqueue_type_check nil
94
+
95
+ when :"textDocument/completion"
96
+ Steep.logger.error request.inspect
97
+ begin
98
+ params = request[:params]
99
+ uri = URI.parse(params[:textDocument][:uri])
100
+ path = project.relative_path(Pathname(uri.path))
101
+ target = project.targets.find {|target| target.source_file?(path) }
102
+ case (status = target&.status)
103
+ when Project::Target::TypeCheckStatus
104
+ subtyping = status.subtyping
105
+ source = target.source_files[path]
106
+
107
+ line, column = params[:position].yield_self {|hash| [hash[:line]+1, hash[:character]] }
108
+ trigger = params[:context][:triggerCharacter]
109
+
110
+ Steep.logger.error "line: #{line}, column: #{column}, trigger: #{trigger}"
111
+
112
+ provider = Project::CompletionProvider.new(source_text: source.content, path: path, subtyping: subtyping)
113
+ items = begin
114
+ provider.run(line: line, column: column)
115
+ rescue Parser::SyntaxError
116
+ []
117
+ end
118
+
119
+ completion_items = items.map do |item|
120
+ format_completion_item(item)
121
+ end
122
+
123
+ Steep.logger.debug "items = #{completion_items.inspect}"
124
+
125
+ yield id, LanguageServer::Protocol::Interface::CompletionList.new(
126
+ is_incomplete: false,
127
+ items: completion_items
128
+ )
129
+ end
130
+
131
+ rescue Typing::UnknownNodeError => exn
132
+ Steep.log_error exn, message: "Failed to compute completion: #{exn.inspect}"
133
+ yield id, nil
134
+ end
135
+
91
136
  when :"textDocument/didChange"
92
137
  uri = URI.parse(request[:params][:textDocument][:uri])
93
138
  path = project.relative_path(Pathname(uri.path))
@@ -151,7 +196,11 @@ module Steep
151
196
  @type_check_thread = Thread.start do
152
197
  while request = type_check_queue.deq
153
198
  if @latest_update_version == nil || @latest_update_version == request.version
154
- run_type_check()
199
+ begin
200
+ run_type_check()
201
+ rescue => exn
202
+ Steep.log_error exn
203
+ end
155
204
  end
156
205
  end
157
206
  end
@@ -185,13 +234,11 @@ module Steep
185
234
  source.errors.map {|error| diagnostic_for_type_error(error) }
186
235
  when Project::SourceFile::AnnotationSyntaxErrorStatus
187
236
  [diagnostics_raw(source.status.error.message, source.status.location)]
188
- when Project::SourceFile::ParseErrorStatus
189
- []
190
- when Project::SourceFile::TypeCheckErrorStatus
191
- []
192
237
  end
193
238
 
194
- report_diagnostics source.path, diagnostics
239
+ if diagnostics
240
+ report_diagnostics source.path, diagnostics
241
+ end
195
242
  end
196
243
  when Project::Target::SignatureSyntaxErrorStatus
197
244
  Steep.logger.info { "Signature syntax error" }
@@ -280,6 +327,9 @@ module Steep
280
327
  range: range
281
328
  )
282
329
  end
330
+ rescue Typing::UnknownNodeError => exn
331
+ Steep.log_error exn, message: "Failed to compute hover: #{exn.inspect}"
332
+ nil
283
333
  end
284
334
 
285
335
  def format_hover(content)
@@ -331,6 +381,126 @@ HOVER
331
381
  "`#{content.type}`"
332
382
  end
333
383
  end
384
+
385
+ def format_completion_item(item)
386
+ range = LanguageServer::Protocol::Interface::Range.new(
387
+ start: LanguageServer::Protocol::Interface::Position.new(
388
+ line: item.range.start.line-1,
389
+ character: item.range.start.column
390
+ ),
391
+ end: LanguageServer::Protocol::Interface::Position.new(
392
+ line: item.range.end.line-1,
393
+ character: item.range.end.column
394
+ )
395
+ )
396
+
397
+ case item
398
+ when Project::CompletionProvider::LocalVariableItem
399
+ LanguageServer::Protocol::Interface::CompletionItem.new(
400
+ label: item.identifier,
401
+ kind: LanguageServer::Protocol::Constant::CompletionItemKind::VARIABLE,
402
+ detail: "#{item.identifier}: #{item.type}",
403
+ text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
404
+ range: range,
405
+ new_text: "#{item.identifier}"
406
+ )
407
+ )
408
+ when Project::CompletionProvider::MethodNameItem
409
+ label = "def #{item.identifier}: #{item.method_type}"
410
+ method_type_snippet = method_type_to_snippet(item.method_type)
411
+ LanguageServer::Protocol::Interface::CompletionItem.new(
412
+ label: label,
413
+ kind: LanguageServer::Protocol::Constant::CompletionItemKind::METHOD,
414
+ text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
415
+ new_text: "#{item.identifier}#{method_type_snippet}",
416
+ range: range
417
+ ),
418
+ documentation: item.definition.comment&.string,
419
+ insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET
420
+ )
421
+ when Project::CompletionProvider::InstanceVariableItem
422
+ label = "#{item.identifier}: #{item.type}"
423
+ LanguageServer::Protocol::Interface::CompletionItem.new(
424
+ label: label,
425
+ kind: LanguageServer::Protocol::Constant::CompletionItemKind::FIELD,
426
+ text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
427
+ range: range,
428
+ new_text: item.identifier,
429
+ ),
430
+ insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET
431
+ )
432
+ end
433
+ end
434
+
435
+ def method_type_to_snippet(method_type)
436
+ params = if method_type.type.each_param.count == 0
437
+ ""
438
+ else
439
+ "(#{params_to_snippet(method_type.type)})"
440
+ end
441
+
442
+
443
+ block = if method_type.block
444
+ open, space, close = if method_type.block.type.return_type.is_a?(Ruby::Signature::Types::Bases::Void)
445
+ ["do", " ", "end"]
446
+ else
447
+ ["{", "", "}"]
448
+ end
449
+
450
+ if method_type.block.type.each_param.count == 0
451
+ " #{open} $0 #{close}"
452
+ else
453
+ " #{open}#{space}|#{params_to_snippet(method_type.block.type)}| $0 #{close}"
454
+ end
455
+ else
456
+ ""
457
+ end
458
+
459
+ "#{params}#{block}"
460
+ end
461
+
462
+ def params_to_snippet(fun)
463
+ params = []
464
+
465
+ index = 1
466
+
467
+ fun.required_positionals.each do |param|
468
+ if name = param.name
469
+ params << "${#{index}:#{param.type}}"
470
+ else
471
+ params << "${#{index}:#{param.type}}"
472
+ end
473
+
474
+ index += 1
475
+ end
476
+
477
+ if fun.rest_positionals
478
+ params << "${#{index}:*#{fun.rest_positionals.type}}"
479
+ index += 1
480
+ end
481
+
482
+ fun.trailing_positionals.each do |param|
483
+ if name = param.name
484
+ params << "${#{index}:#{param.type}}"
485
+ else
486
+ params << "${#{index}:#{param.type}}"
487
+ end
488
+
489
+ index += 1
490
+ end
491
+
492
+ fun.required_keywords.each do |keyword, param|
493
+ if name = param.name
494
+ params << "#{keyword}: ${#{index}:#{name}_}"
495
+ else
496
+ params << "#{keyword}: ${#{index}:#{param.type}_}"
497
+ end
498
+
499
+ index += 1
500
+ end
501
+
502
+ params.join(", ")
503
+ end
334
504
  end
335
505
  end
336
506
  end
@@ -0,0 +1,302 @@
1
+ module Steep
2
+ class Project
3
+ class CompletionProvider
4
+ Position = Struct.new(:line, :column, keyword_init: true) do
5
+ def -(size)
6
+ Position.new(line: line, column: column - size)
7
+ end
8
+ end
9
+ Range = Struct.new(:start, :end, keyword_init: true)
10
+
11
+ InstanceVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
12
+ LocalVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
13
+ MethodNameItem = Struct.new(:identifier, :range, :definition, :method_type, keyword_init: true)
14
+
15
+ attr_reader :source_text
16
+ attr_reader :path
17
+ attr_reader :subtyping
18
+ attr_reader :modified_text
19
+ attr_reader :source
20
+ attr_reader :typing
21
+
22
+ def initialize(source_text:, path:, subtyping:)
23
+ @source_text = source_text
24
+ @path = path
25
+ @subtyping = subtyping
26
+ end
27
+
28
+ def type_check!(text)
29
+ @modified_text = text
30
+
31
+ Steep.measure "parsing" do
32
+ @source = SourceFile.parse(text, path: path, factory: subtyping.factory)
33
+ end
34
+
35
+ Steep.measure "typechecking" do
36
+ @typing = SourceFile.type_check(source, subtyping: subtyping)
37
+ end
38
+ end
39
+
40
+ def run(line:, column:)
41
+ source_text = self.source_text.dup
42
+ index = index_for(source_text, line:line, column: column)
43
+ possible_trigger = source_text[index-1]
44
+
45
+ Steep.logger.debug "possible_trigger: #{possible_trigger.inspect}"
46
+
47
+ position = Position.new(line: line, column: column)
48
+
49
+ begin
50
+ Steep.measure "type_check!" do
51
+ type_check!(source_text)
52
+ end
53
+
54
+ Steep.measure "completion item collection" do
55
+ items_for_trigger(position: position)
56
+ end
57
+
58
+ rescue Parser::SyntaxError => exn
59
+ Steep.logger.error "recovering syntax error: #{exn.inspect}"
60
+ case possible_trigger
61
+ when "."
62
+ source_text[index-1] = " "
63
+ type_check!(source_text)
64
+ items_for_dot(position: position)
65
+ when "@"
66
+ source_text[index-1] = " "
67
+ type_check!(source_text)
68
+ items_for_atmark(position: position)
69
+ else
70
+ []
71
+ end
72
+ end
73
+ end
74
+
75
+ def range_from_loc(loc)
76
+ Range.new(
77
+ start: Position.new(line: loc.line, column: loc.column),
78
+ end: Position.new(line: loc.last_line, column: loc.last_line)
79
+ )
80
+ end
81
+
82
+ def at_end?(pos, of:)
83
+ of.last_line == pos.line && of.last_column == pos.column
84
+ end
85
+
86
+ def range_for(position, prefix: "")
87
+ if prefix.empty?
88
+ Range.new(start: position, end: position)
89
+ else
90
+ Range.new(start: position - prefix.size, end: position)
91
+ end
92
+ end
93
+
94
+ def items_for_trigger(position:)
95
+ node, *parents = source.find_nodes(line: position.line, column: position.column)
96
+ node ||= source.node
97
+
98
+ return [] unless node
99
+
100
+ items = []
101
+
102
+ case
103
+ when node.type == :send && node.children[0] == nil && at_end?(position, of: node.loc.selector)
104
+ # foo ←
105
+ context = typing.context_of(node: node)
106
+ prefix = node.children[1].to_s
107
+
108
+ method_items_for_receiver_type(context.self_type,
109
+ include_private: true,
110
+ prefix: prefix,
111
+ position: position,
112
+ items: items)
113
+ local_variable_items_for_context(context, position: position, prefix: prefix, items: items)
114
+
115
+ when node.type == :lvar && at_end?(position, of: node.loc)
116
+ # foo ← (lvar)
117
+ context = typing.context_of(node: node)
118
+ local_variable_items_for_context(context, position: position, prefix: node.children[0].name.to_s, items: items)
119
+
120
+ when node.type == :send && node.children[0] && at_end?(position, of: node.loc.selector)
121
+ # foo.ba ←
122
+ context = typing.context_of(node: node)
123
+ receiver_type = case (type = typing.type_of(node: node.children[0]))
124
+ when AST::Types::Self
125
+ context.self_type
126
+ else
127
+ type
128
+ end
129
+ prefix = node.children[1].to_s
130
+
131
+ method_items_for_receiver_type(receiver_type,
132
+ include_private: false,
133
+ prefix: prefix,
134
+ position: position,
135
+ items: items)
136
+
137
+ when node.type == :const && node.children[0] == nil && at_end?(position, of: node.loc)
138
+ # Foo ← (const)
139
+ context = typing.context_of(node: node)
140
+ prefix = node.children[1].to_s
141
+
142
+ method_items_for_receiver_type(context.self_type,
143
+ include_private: false,
144
+ prefix: prefix,
145
+ position: position,
146
+ items: items)
147
+
148
+ when node.type == :send && at_end?(position, of: node.loc.dot)
149
+ # foo.← ba
150
+ context = typing.context_of(node: node)
151
+ receiver_type = case (type = typing.type_of(node: node.children[0]))
152
+ when AST::Types::Self
153
+ context.self_type
154
+ else
155
+ type
156
+ end
157
+
158
+ method_items_for_receiver_type(receiver_type,
159
+ include_private: false,
160
+ prefix: "",
161
+ position: position,
162
+ items: items)
163
+
164
+ when node.type == :ivar && at_end?(position, of: node.loc)
165
+ # @fo ←
166
+ context = typing.context_of(node: node)
167
+ instance_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
168
+
169
+ else
170
+ context = typing.context_of(node: node)
171
+
172
+ method_items_for_receiver_type(context.self_type,
173
+ include_private: true,
174
+ prefix: "",
175
+ position: position,
176
+ items: items)
177
+ local_variable_items_for_context(context, position: position, prefix: "", items: items)
178
+ instance_variable_items_for_context(context, position: position, prefix: "", items: items)
179
+ end
180
+
181
+ items
182
+ end
183
+
184
+ def items_for_dot(position:)
185
+ # foo. ←
186
+ shift_pos = position-1
187
+ node, *parents = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
188
+ node ||= source.node
189
+
190
+ return [] unless node
191
+
192
+ if at_end?(shift_pos, of: node.loc)
193
+ context = typing.context_of(node: node)
194
+ receiver_type = case (type = typing.type_of(node: node))
195
+ when AST::Types::Self
196
+ context.self_type
197
+ else
198
+ type
199
+ end
200
+
201
+ items = []
202
+ method_items_for_receiver_type(receiver_type,
203
+ include_private: false,
204
+ prefix: "",
205
+ position: position,
206
+ items: items)
207
+ items
208
+ else
209
+ []
210
+ end
211
+ end
212
+
213
+ def items_for_atmark(position:)
214
+ # @ ←
215
+ shift_pos = position-1
216
+ node, *parents = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
217
+ node ||= source.node
218
+
219
+ return [] unless node
220
+
221
+ context = typing.context_of(node: node)
222
+ items = []
223
+ instance_variable_items_for_context(context, prefix: "", position: position, items: items)
224
+ items
225
+ end
226
+
227
+ def method_items_for_receiver_type(type, include_private:, prefix:, position:, items:)
228
+ range = range_for(position, prefix: prefix)
229
+ definition = case type
230
+ when AST::Types::Name::Instance
231
+ type_name = subtyping.factory.type_name_1(type.name)
232
+ subtyping.factory.definition_builder.build_instance(type_name)
233
+ when AST::Types::Name::Class, AST::Types::Name::Module
234
+ type_name = subtyping.factory.type_name_1(type.name)
235
+ subtyping.factory.definition_builder.build_singleton(type_name)
236
+ when AST::Types::Name::Interface
237
+ type_name = subtyping.factory.type_name_1(type.name)
238
+ interface = subtyping.factory.env.find_class(type_name)
239
+ subtyping.factory.definition_builder.build_interface(type_name, interface)
240
+ end
241
+
242
+ if definition
243
+ definition.methods.each do |name, method|
244
+ if include_private || method.public?
245
+ if name.to_s.start_with?(prefix)
246
+ if word_name?(name.to_s)
247
+ method.method_types.each do |method_type|
248
+ items << MethodNameItem.new(identifier: name,
249
+ range: range,
250
+ definition: method,
251
+ method_type: method_type)
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ def word_name?(name)
261
+ name =~ /\w/
262
+ end
263
+
264
+ def local_variable_items_for_context(context, position:, prefix:, items:)
265
+ range = range_for(position, prefix: prefix)
266
+ context.type_env.lvar_types.each do |name, type|
267
+ if name.to_s.start_with?(prefix)
268
+ items << LocalVariableItem.new(identifier: name,
269
+ range: range,
270
+ type: type)
271
+ end
272
+ end
273
+ end
274
+
275
+ def instance_variable_items_for_context(context, position:, prefix:, items:)
276
+ range = range_for(position, prefix: prefix)
277
+ context.type_env.ivar_types.map do |name, type|
278
+ if name.to_s.start_with?(prefix)
279
+ items << InstanceVariableItem.new(identifier: name,
280
+ range: range,
281
+ type: type)
282
+ end
283
+ end
284
+ end
285
+
286
+ def index_for(string, line:, column:)
287
+ index = 0
288
+
289
+ string.each_line.with_index do |s, i|
290
+ if i+1 == line
291
+ index += column
292
+ break
293
+ else
294
+ index += s.size
295
+ end
296
+ end
297
+
298
+ index
299
+ end
300
+ end
301
+ end
302
+ end