steep 0.49.1 → 0.52.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/Gemfile +4 -1
- data/Gemfile.lock +8 -5
- data/lib/steep/ast/annotation/collection.rb +10 -8
- data/lib/steep/ast/types/factory.rb +5 -5
- data/lib/steep/cli.rb +83 -1
- data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
- data/lib/steep/diagnostic/ruby.rb +21 -15
- data/lib/steep/drivers/check.rb +1 -0
- data/lib/steep/drivers/langserver.rb +2 -2
- data/lib/steep/drivers/stats.rb +1 -0
- data/lib/steep/drivers/utils/jobs_count.rb +1 -1
- data/lib/steep/drivers/watch.rb +1 -1
- data/lib/steep/index/source_index.rb +18 -1
- data/lib/steep/interface/function.rb +5 -0
- data/lib/steep/module_helper.rb +4 -7
- data/lib/steep/project.rb +15 -1
- data/lib/steep/server/interaction_worker.rb +47 -4
- data/lib/steep/server/master.rb +10 -5
- data/lib/steep/server/type_check_worker.rb +19 -4
- data/lib/steep/server/worker_process.rb +15 -6
- data/lib/steep/services/completion_provider.rb +109 -1
- data/lib/steep/services/goto_service.rb +23 -10
- data/lib/steep/services/hover_content.rb +52 -4
- data/lib/steep/services/type_check_service.rb +6 -3
- data/lib/steep/source.rb +71 -18
- data/lib/steep/type_construction.rb +209 -162
- data/lib/steep/type_inference/constant_env.rb +33 -15
- data/lib/steep/type_inference/context.rb +6 -7
- data/lib/steep/type_inference/type_env.rb +16 -54
- data/lib/steep/version.rb +1 -1
- data/smoke/const/test_expectations.yml +24 -19
- data/smoke/diagnostics/test_expectations.yml +77 -17
- data/smoke/integer/test_expectations.yml +24 -4
- data/smoke/method/test_expectations.yml +30 -0
- data/smoke/regression/test_expectations.yml +24 -0
- data/smoke/yield/test_expectations.yml +20 -0
- data/steep.gemspec +1 -1
- metadata +5 -4
@@ -135,6 +135,21 @@ module Steep
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def handle_job(job)
|
138
|
+
job_path = if job.respond_to?(:path)
|
139
|
+
if Gem.win_platform?
|
140
|
+
# FIXME: Sometimes drive letter is missing, using base_dir
|
141
|
+
if job.path.to_s.start_with?(%r{/[a-z](:|%3A)/}i)
|
142
|
+
job.path.to_s
|
143
|
+
else
|
144
|
+
"/#{project.base_dir.to_s.split("/").first}/#{job.path}"
|
145
|
+
end
|
146
|
+
else
|
147
|
+
job.path.to_s
|
148
|
+
end
|
149
|
+
else
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
138
153
|
case job
|
139
154
|
when StartTypeCheckJob
|
140
155
|
Steep.logger.info { "Processing StartTypeCheckJob for guid=#{job.guid}" }
|
@@ -149,7 +164,7 @@ module Steep
|
|
149
164
|
writer.write(
|
150
165
|
method: :"textDocument/publishDiagnostics",
|
151
166
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
152
|
-
uri: URI.parse(
|
167
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
153
168
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
|
154
169
|
)
|
155
170
|
)
|
@@ -167,7 +182,7 @@ module Steep
|
|
167
182
|
writer.write(
|
168
183
|
method: :"textDocument/publishDiagnostics",
|
169
184
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
170
|
-
uri: URI.parse(
|
185
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
171
186
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
|
172
187
|
)
|
173
188
|
)
|
@@ -186,7 +201,7 @@ module Steep
|
|
186
201
|
writer.write(
|
187
202
|
method: :"textDocument/publishDiagnostics",
|
188
203
|
params: LSP::Interface::PublishDiagnosticsParams.new(
|
189
|
-
uri: URI.parse(
|
204
|
+
uri: URI.parse(job_path).tap {|uri| uri.scheme = "file"},
|
190
205
|
diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
|
191
206
|
)
|
192
207
|
)
|
@@ -268,7 +283,7 @@ module Steep
|
|
268
283
|
line = job.params[:position][:line] + 1
|
269
284
|
column = job.params[:position][:character]
|
270
285
|
|
271
|
-
goto_service = Services::GotoService.new(type_check: service)
|
286
|
+
goto_service = Services::GotoService.new(type_check: service, assignment: assignment)
|
272
287
|
locations =
|
273
288
|
case
|
274
289
|
when job.definition?
|
@@ -18,13 +18,17 @@ module Steep
|
|
18
18
|
@index = index
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.spawn_worker(type, name:, steepfile:, options: [], delay_shutdown: false, index: nil)
|
22
|
-
|
21
|
+
def self.spawn_worker(type, name:, steepfile:, steep_command: "steep", options: [], delay_shutdown: false, index: nil)
|
22
|
+
args = ["--name=#{name}", "--steepfile=#{steepfile}"]
|
23
|
+
args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" })
|
24
|
+
if Steep.log_output.is_a?(String)
|
25
|
+
args << "--log-output=#{Steep.log_output}"
|
26
|
+
end
|
23
27
|
command = case type
|
24
28
|
when :interaction
|
25
|
-
[
|
29
|
+
[steep_command, "worker", "--interaction", *args, *options]
|
26
30
|
when :typecheck
|
27
|
-
[
|
31
|
+
[steep_command, "worker", "--typecheck", *args, *options]
|
28
32
|
else
|
29
33
|
raise "Unknown type: #{type}"
|
30
34
|
end
|
@@ -33,7 +37,11 @@ module Steep
|
|
33
37
|
command << "--delay-shutdown"
|
34
38
|
end
|
35
39
|
|
36
|
-
stdin, stdout, thread =
|
40
|
+
stdin, stdout, thread = if Gem.win_platform?
|
41
|
+
Open3.popen2(*command, new_pgroup: true)
|
42
|
+
else
|
43
|
+
Open3.popen2(*command, pgroup: true)
|
44
|
+
end
|
37
45
|
stderr = nil
|
38
46
|
|
39
47
|
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
|
@@ -42,11 +50,12 @@ module Steep
|
|
42
50
|
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index)
|
43
51
|
end
|
44
52
|
|
45
|
-
def self.spawn_typecheck_workers(steepfile:, args:, count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false)
|
53
|
+
def self.spawn_typecheck_workers(steepfile:, args:, steep_command: "steep", count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false)
|
46
54
|
count.times.map do |i|
|
47
55
|
spawn_worker(:typecheck,
|
48
56
|
name: "typecheck@#{i}",
|
49
57
|
steepfile: steepfile,
|
58
|
+
steep_command: steep_command,
|
50
59
|
options: ["--max-index=#{count}", "--index=#{i}", *args],
|
51
60
|
delay_shutdown: delay_shutdown,
|
52
61
|
index: i)
|
@@ -10,6 +10,30 @@ module Steep
|
|
10
10
|
|
11
11
|
InstanceVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
|
12
12
|
LocalVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
|
13
|
+
ConstantItem = Struct.new(:env, :identifier, :range, :type, :full_name, keyword_init: true) do
|
14
|
+
def class?
|
15
|
+
if decl = env.class_decls[full_name]
|
16
|
+
decl.primary.decl.is_a?(RBS::AST::Declarations::Class)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def module?
|
21
|
+
if decl = env.class_decls[full_name]
|
22
|
+
decl.primary.decl.is_a?(RBS::AST::Declarations::Module)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def comments
|
27
|
+
case
|
28
|
+
when decl = env.class_decls[full_name]
|
29
|
+
decl.decls.filter_map {|d| d.decl.comment }
|
30
|
+
when comment = env.constant_decls[full_name]&.decl&.comment
|
31
|
+
[comment]
|
32
|
+
else
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
13
37
|
MethodNameItem = Struct.new(:identifier, :range, :receiver_type, :method_type, :method_decls, keyword_init: true) do
|
14
38
|
def comment
|
15
39
|
case method_decls.size
|
@@ -61,6 +85,10 @@ module Steep
|
|
61
85
|
end
|
62
86
|
end
|
63
87
|
|
88
|
+
def env
|
89
|
+
subtyping.factory.env
|
90
|
+
end
|
91
|
+
|
64
92
|
def run(line:, column:)
|
65
93
|
source_text = self.source_text.dup
|
66
94
|
index = index_for(source_text, line:line, column: column)
|
@@ -92,6 +120,15 @@ module Steep
|
|
92
120
|
source_text[index-1] = " "
|
93
121
|
type_check!(source_text, line: line, column: column)
|
94
122
|
items_for_atmark(position: position)
|
123
|
+
when ":"
|
124
|
+
if source_text[index-2] == ":"
|
125
|
+
source_text[index-1] = " "
|
126
|
+
source_text[index-2] = " "
|
127
|
+
type_check!(source_text, line: line, column: column)
|
128
|
+
items_for_colon2(position: position)
|
129
|
+
else
|
130
|
+
[]
|
131
|
+
end
|
95
132
|
else
|
96
133
|
[]
|
97
134
|
end
|
@@ -170,8 +207,25 @@ module Steep
|
|
170
207
|
prefix: prefix,
|
171
208
|
position: position,
|
172
209
|
items: items)
|
210
|
+
constant_items_for_context(context, prefix: prefix, position: position, items: items)
|
173
211
|
|
174
|
-
when node.type == :
|
212
|
+
when node.type == :const && node.children[0] && at_end?(position, of: node.loc)
|
213
|
+
# Foo::Ba ← (const)
|
214
|
+
parent_node = node.children[0]
|
215
|
+
parent_type = typing.type_of(node: parent_node)
|
216
|
+
|
217
|
+
if parent_type
|
218
|
+
prefix = node.children[1].to_s
|
219
|
+
|
220
|
+
method_items_for_receiver_type(parent_type,
|
221
|
+
include_private: false,
|
222
|
+
prefix: prefix,
|
223
|
+
position: position,
|
224
|
+
items: items)
|
225
|
+
constant_items_for_context(context, parent: parent_node, prefix: prefix, position: position, items: items)
|
226
|
+
end
|
227
|
+
|
228
|
+
when node.type == :send && at_end?(position, of: node.loc.dot) && node.loc.dot.source == "."
|
175
229
|
# foo.← ba
|
176
230
|
receiver_type = case (type = typing.type_of(node: node.children[0]))
|
177
231
|
when AST::Types::Self
|
@@ -186,6 +240,10 @@ module Steep
|
|
186
240
|
position: position,
|
187
241
|
items: items)
|
188
242
|
|
243
|
+
when node.type == :send && at_end?(position, of: node.loc.dot) && node.loc.dot.source == "::"
|
244
|
+
# foo::← ba
|
245
|
+
items.push(*items_for_colon2(position: position))
|
246
|
+
|
189
247
|
when node.type == :ivar && at_end?(position, of: node.loc)
|
190
248
|
# @fo ←
|
191
249
|
instance_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
@@ -198,6 +256,7 @@ module Steep
|
|
198
256
|
items: items)
|
199
257
|
local_variable_items_for_context(context, position: position, prefix: "", items: items)
|
200
258
|
instance_variable_items_for_context(context, position: position, prefix: "", items: items)
|
259
|
+
constant_items_for_context(context, position: position, prefix: "", items: items)
|
201
260
|
end
|
202
261
|
|
203
262
|
items
|
@@ -236,6 +295,31 @@ module Steep
|
|
236
295
|
end
|
237
296
|
end
|
238
297
|
|
298
|
+
def items_for_colon2(position:)
|
299
|
+
# :: ←
|
300
|
+
shift_pos = position-2
|
301
|
+
node, *_ = source.find_nodes(line: shift_pos.line, column: shift_pos.column)
|
302
|
+
node ||= source.node
|
303
|
+
|
304
|
+
items = []
|
305
|
+
case node&.type
|
306
|
+
when :const
|
307
|
+
# Constant:: ←
|
308
|
+
context = typing.context_at(line: position.line, column: position.column)
|
309
|
+
constant_items_for_context(context, parent: node, position: position, items: items, prefix: "")
|
310
|
+
when nil
|
311
|
+
# :: ←
|
312
|
+
context = typing.context_at(line: position.line, column: position.column)
|
313
|
+
constant_items_for_context(context, parent: nil, position: position, items: items, prefix: "")
|
314
|
+
end
|
315
|
+
|
316
|
+
if node
|
317
|
+
items.push(*items_for_dot(position: position - 1))
|
318
|
+
end
|
319
|
+
|
320
|
+
items
|
321
|
+
end
|
322
|
+
|
239
323
|
def items_for_atmark(position:)
|
240
324
|
# @ ←
|
241
325
|
shift_pos = position-1
|
@@ -290,6 +374,30 @@ module Steep
|
|
290
374
|
end
|
291
375
|
end
|
292
376
|
|
377
|
+
def constant_items_for_context(context, parent: nil, position:, prefix:, items:)
|
378
|
+
range = range_for(position, prefix: prefix)
|
379
|
+
|
380
|
+
if parent
|
381
|
+
case parent.type
|
382
|
+
when :const
|
383
|
+
const_name = typing.source_index.reference(constant_node: parent)
|
384
|
+
consts = context.module_context.const_env.children(const_name)
|
385
|
+
end
|
386
|
+
else
|
387
|
+
consts = context.module_context.const_env.constants
|
388
|
+
end
|
389
|
+
|
390
|
+
if consts
|
391
|
+
consts.each do |name, tuple|
|
392
|
+
type, full_name, _ = tuple
|
393
|
+
|
394
|
+
if name.to_s.start_with?(prefix)
|
395
|
+
items << ConstantItem.new(env: env, identifier: name, range: range, type: type, full_name: full_name)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
293
401
|
def instance_variable_items_for_context(context, position:, prefix:, items:)
|
294
402
|
range = range_for(position, prefix: prefix)
|
295
403
|
context.type_env.ivar_types.map do |name, type|
|
@@ -21,10 +21,11 @@ module Steep
|
|
21
21
|
end
|
22
22
|
TypeNameQuery = Struct.new(:name, keyword_init: true)
|
23
23
|
|
24
|
-
attr_reader :type_check
|
24
|
+
attr_reader :type_check, :assignment
|
25
25
|
|
26
|
-
def initialize(type_check:)
|
26
|
+
def initialize(type_check:, assignment:)
|
27
27
|
@type_check = type_check
|
28
|
+
@assignment = assignment
|
28
29
|
end
|
29
30
|
|
30
31
|
def project
|
@@ -78,7 +79,17 @@ module Steep
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
+
# Drop un-assigned paths here.
|
83
|
+
# The path assignment makes sense only for `.rbs` files, because un-assigned `.rb` files are already skipped since they are not type checked.
|
84
|
+
#
|
85
|
+
locations.uniq.select do |loc|
|
86
|
+
case loc
|
87
|
+
when RBS::Location
|
88
|
+
assignment =~ loc.name
|
89
|
+
else
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
82
93
|
end
|
83
94
|
|
84
95
|
def test_ast_location(loc, line:, column:)
|
@@ -100,14 +111,13 @@ module Steep
|
|
100
111
|
typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
|
101
112
|
if typing
|
102
113
|
node, *parents = typing.source.find_nodes(line: line, column: column)
|
114
|
+
|
103
115
|
if node
|
104
116
|
case node.type
|
105
117
|
when :const, :casgn
|
106
118
|
if test_ast_location(node.location.name, line: line, column: column)
|
107
|
-
if
|
108
|
-
|
109
|
-
const = const_env.lookup_constant(module_name_from_node(node))
|
110
|
-
queries << ConstantQuery.new(name: const.name, from: :ruby)
|
119
|
+
if name = typing.source_index.reference(constant_node: node)
|
120
|
+
queries << ConstantQuery.new(name: name, from: :ruby)
|
111
121
|
end
|
112
122
|
end
|
113
123
|
when :def, :defs
|
@@ -125,7 +135,10 @@ module Steep
|
|
125
135
|
end
|
126
136
|
when :send
|
127
137
|
if test_ast_location(node.location.selector, line: line, column: column)
|
128
|
-
|
138
|
+
if (parent = parents[0]) && parent.type == :block && parent.children[0] == node
|
139
|
+
node = parents[0]
|
140
|
+
end
|
141
|
+
|
129
142
|
case call = typing.call_of(node: node)
|
130
143
|
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
131
144
|
call.method_decls.each do |decl|
|
@@ -232,8 +245,8 @@ module Steep
|
|
232
245
|
entry = typing.source_index.entry(constant: name)
|
233
246
|
entry.definitions.each do |node|
|
234
247
|
case node.type
|
235
|
-
when :
|
236
|
-
locations << node.
|
248
|
+
when :const
|
249
|
+
locations << node.location.expression
|
237
250
|
when :casgn
|
238
251
|
parent = node.children[0]
|
239
252
|
location =
|
@@ -5,16 +5,42 @@ module Steep
|
|
5
5
|
VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
|
6
6
|
MethodCallContent = Struct.new(:node, :method_name, :type, :definition, :location, keyword_init: true)
|
7
7
|
DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
|
8
|
-
TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
|
9
|
-
ClassContent = Struct.new(:location, :decl, keyword_init: true)
|
10
|
-
InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
|
11
|
-
|
12
8
|
def comment_string
|
13
9
|
if comments = definition&.comments
|
14
10
|
comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
14
|
+
ConstantContent = Struct.new(:location, :full_name, :type, :decl, keyword_init: true) do
|
15
|
+
def comment_string
|
16
|
+
if class_or_module?
|
17
|
+
comments = decl.decls.filter_map {|d| d.decl.comment&.string }
|
18
|
+
unless comments.empty?
|
19
|
+
return comments.join("\n----\n")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if constant?
|
24
|
+
if comment = decl.decl.comment
|
25
|
+
return comment.string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def constant?
|
33
|
+
decl.is_a?(RBS::Environment::SingleEntry)
|
34
|
+
end
|
35
|
+
|
36
|
+
def class_or_module?
|
37
|
+
decl.is_a?(RBS::Environment::MultiEntry)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
|
42
|
+
ClassContent = Struct.new(:location, :decl, keyword_init: true)
|
43
|
+
InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
|
18
44
|
|
19
45
|
InstanceMethodName = Struct.new(:class_name, :method_name)
|
20
46
|
SingletonMethodName = Struct.new(:class_name, :method_name)
|
@@ -190,6 +216,28 @@ module Steep
|
|
190
216
|
location: node.loc.expression
|
191
217
|
)
|
192
218
|
end
|
219
|
+
when :const, :casgn
|
220
|
+
context = typing.context_at(line: line, column: column)
|
221
|
+
|
222
|
+
type = typing.type_of(node: node)
|
223
|
+
const_name = typing.source_index.reference(constant_node: node)
|
224
|
+
|
225
|
+
if const_name
|
226
|
+
decl = context.env.class_decls[const_name] || context.env.constant_decls[const_name]
|
227
|
+
|
228
|
+
ConstantContent.new(
|
229
|
+
location: node.location.name,
|
230
|
+
full_name: const_name,
|
231
|
+
type: type,
|
232
|
+
decl: decl
|
233
|
+
)
|
234
|
+
else
|
235
|
+
TypeContent.new(
|
236
|
+
node: node,
|
237
|
+
type: type,
|
238
|
+
location: node.location.expression
|
239
|
+
)
|
240
|
+
end
|
193
241
|
else
|
194
242
|
type = typing.type_of(node: node)
|
195
243
|
|
@@ -338,8 +338,12 @@ module Steep
|
|
338
338
|
end
|
339
339
|
|
340
340
|
def self.type_check(source:, subtyping:)
|
341
|
-
annotations = source.annotations(block: source.node, factory: subtyping.factory,
|
342
|
-
const_env = TypeInference::ConstantEnv.new(
|
341
|
+
annotations = source.annotations(block: source.node, factory: subtyping.factory, context: nil)
|
342
|
+
const_env = TypeInference::ConstantEnv.new(
|
343
|
+
factory: subtyping.factory,
|
344
|
+
context: nil,
|
345
|
+
resolver: RBS::Resolver::ConstantResolver.new(builder: subtyping.factory.definition_builder)
|
346
|
+
)
|
343
347
|
type_env = TypeInference::TypeEnv.build(annotations: annotations,
|
344
348
|
subtyping: subtyping,
|
345
349
|
const_env: const_env,
|
@@ -357,7 +361,6 @@ module Steep
|
|
357
361
|
instance_type: AST::Builtin::Object.instance_type,
|
358
362
|
module_type: AST::Builtin::Object.module_type,
|
359
363
|
implement_name: nil,
|
360
|
-
current_namespace: RBS::Namespace.root,
|
361
364
|
const_env: const_env,
|
362
365
|
class_name: AST::Builtin::Object.module_name,
|
363
366
|
instance_definition: subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name),
|
data/lib/steep/source.rb
CHANGED
@@ -283,11 +283,11 @@ module Steep
|
|
283
283
|
node.updated(nil, children)
|
284
284
|
end
|
285
285
|
|
286
|
-
def annotations(block:, factory:,
|
286
|
+
def annotations(block:, factory:, context:)
|
287
287
|
AST::Annotation::Collection.new(
|
288
288
|
annotations: (mapping[block] || []).map(&:annotation),
|
289
289
|
factory: factory,
|
290
|
-
|
290
|
+
context: context
|
291
291
|
)
|
292
292
|
end
|
293
293
|
|
@@ -301,11 +301,42 @@ module Steep
|
|
301
301
|
end
|
302
302
|
end
|
303
303
|
|
304
|
-
def
|
305
|
-
|
306
|
-
node.
|
307
|
-
|
304
|
+
def each_heredoc_node(node = self.node, parents = [], &block)
|
305
|
+
if block
|
306
|
+
case node.type
|
307
|
+
when :dstr, :str
|
308
|
+
if node.location.is_a?(Parser::Source::Map::Heredoc)
|
309
|
+
yield [node, *parents]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
parents.unshift(node)
|
314
|
+
Source.each_child_node(node) do |child|
|
315
|
+
each_heredoc_node(child, parents, &block)
|
316
|
+
end
|
317
|
+
parents.shift()
|
318
|
+
else
|
319
|
+
enum_for :each_heredoc_node, node
|
320
|
+
end
|
321
|
+
end
|
308
322
|
|
323
|
+
def find_heredoc_nodes(line, column, position)
|
324
|
+
each_heredoc_node() do |nodes|
|
325
|
+
node = nodes[0]
|
326
|
+
|
327
|
+
range = node.location.heredoc_body&.yield_self do |r|
|
328
|
+
r.begin_pos..r.end_pos
|
329
|
+
end
|
330
|
+
|
331
|
+
if range && (range === position)
|
332
|
+
return nodes
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
nil
|
337
|
+
end
|
338
|
+
|
339
|
+
def find_nodes_loc(node, position, parents)
|
309
340
|
range = node.location.expression&.yield_self do |r|
|
310
341
|
r.begin_pos..r.end_pos
|
311
342
|
end
|
@@ -315,7 +346,7 @@ module Steep
|
|
315
346
|
parents.unshift node
|
316
347
|
|
317
348
|
Source.each_child_node(node) do |child|
|
318
|
-
ns =
|
349
|
+
ns = find_nodes_loc(child, position, parents) and return ns
|
319
350
|
end
|
320
351
|
|
321
352
|
parents
|
@@ -323,6 +354,24 @@ module Steep
|
|
323
354
|
end
|
324
355
|
end
|
325
356
|
|
357
|
+
def find_nodes(line:, column:)
|
358
|
+
return [] unless node
|
359
|
+
|
360
|
+
position = (line-1).times.sum do |i|
|
361
|
+
node.location.expression.source_buffer.source_line(i+1).size + 1
|
362
|
+
end + column
|
363
|
+
|
364
|
+
if nodes = find_heredoc_nodes(line, column, position)
|
365
|
+
Source.each_child_node(nodes[0]) do |child|
|
366
|
+
find_nodes_loc(child, position, nodes) and break
|
367
|
+
end
|
368
|
+
|
369
|
+
nodes
|
370
|
+
else
|
371
|
+
find_nodes_loc(node, position, [])
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
326
375
|
def self.delete_defs(node, allow_list)
|
327
376
|
case node.type
|
328
377
|
when :def
|
@@ -345,22 +394,26 @@ module Steep
|
|
345
394
|
end
|
346
395
|
|
347
396
|
def without_unrelated_defs(line:, column:)
|
348
|
-
|
349
|
-
|
397
|
+
if node
|
398
|
+
nodes = find_nodes(line: line, column: column) || []
|
399
|
+
defs = Set[].compare_by_identity.merge(nodes.select {|node| node.type == :def || node.type == :defs })
|
350
400
|
|
351
|
-
|
401
|
+
node_ = Source.delete_defs(node, defs)
|
352
402
|
|
353
|
-
|
403
|
+
mapping = {}.compare_by_identity
|
354
404
|
|
355
|
-
|
356
|
-
|
405
|
+
annotations = self.mapping.values.flatten
|
406
|
+
Source.construct_mapping(node: node_, annotations: annotations, mapping: mapping)
|
357
407
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
408
|
+
annotations.each do |annot|
|
409
|
+
mapping[node] ||= []
|
410
|
+
mapping[node] << annot
|
411
|
+
end
|
362
412
|
|
363
|
-
|
413
|
+
Source.new(path: path, node: node_, mapping: mapping)
|
414
|
+
else
|
415
|
+
self
|
416
|
+
end
|
364
417
|
end
|
365
418
|
|
366
419
|
def compact_siblings(node)
|