steep 1.2.1 → 1.3.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +4 -4
- data/Gemfile.steep +1 -1
- data/Gemfile.steep.lock +13 -3
- data/Steepfile +0 -1
- data/lib/steep/annotation_parser.rb +34 -28
- data/lib/steep/ast/annotation.rb +16 -5
- data/lib/steep/ast/node/type_application.rb +74 -0
- data/lib/steep/ast/node/type_assertion.rb +56 -0
- data/lib/steep/ast/types/factory.rb +5 -1
- data/lib/steep/diagnostic/helper.rb +2 -1
- data/lib/steep/diagnostic/lsp_formatter.rb +3 -1
- data/lib/steep/diagnostic/ruby.rb +70 -5
- data/lib/steep/diagnostic/signature.rb +21 -8
- data/lib/steep/drivers/check.rb +1 -1
- data/lib/steep/drivers/checkfile.rb +1 -1
- data/lib/steep/drivers/langserver.rb +2 -2
- data/lib/steep/drivers/stats.rb +1 -1
- data/lib/steep/drivers/watch.rb +1 -1
- data/lib/steep/drivers/worker.rb +0 -1
- data/lib/steep/server/lsp_formatter.rb +13 -3
- data/lib/steep/server/master.rb +4 -1
- data/lib/steep/server/worker_process.rb +86 -14
- data/lib/steep/services/hover_provider/rbs.rb +7 -7
- data/lib/steep/services/hover_provider/ruby.rb +19 -4
- data/lib/steep/services/signature_service.rb +7 -4
- data/lib/steep/signature/validator.rb +36 -13
- data/lib/steep/source.rb +189 -71
- data/lib/steep/type_construction.rb +232 -126
- data/lib/steep/type_inference/logic_type_interpreter.rb +3 -1
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +2 -0
- data/rbs_collection.steep.lock.yaml +27 -10
- data/rbs_collection.steep.yaml +0 -1
- data/sig/shims/exception.rbs +4 -0
- data/sig/shims/parser/comment.rbs +33 -0
- data/sig/shims/parser.rbs +30 -2
- data/sig/steep/annotation_parser.rbs +59 -0
- data/sig/steep/ast/annotation.rbs +21 -26
- data/sig/steep/ast/node/type_application.rbs +31 -0
- data/sig/steep/ast/node/type_assertion.rbs +26 -0
- data/sig/steep/ast/types/factory.rbs +0 -2
- data/sig/steep/diagnostic/helper.rbs +9 -3
- data/sig/steep/diagnostic/lsp_formatter.rbs +12 -8
- data/sig/steep/diagnostic/ruby.rbs +62 -8
- data/sig/steep/diagnostic/signature.rbs +118 -85
- data/sig/steep/drivers/worker.rbs +11 -13
- data/sig/steep/range_extension.rbs +7 -0
- data/sig/steep/server/lsp_formatter.rbs +14 -7
- data/sig/steep/server/worker_process.rbs +74 -12
- data/sig/steep/services/hover_provider/rbs.rbs +27 -7
- data/sig/steep/services/hover_provider/ruby.rbs +18 -4
- data/sig/steep/services/hover_provider/singleton_methods.rbs +1 -1
- data/sig/steep/signature/validator.rbs +76 -0
- data/sig/steep/source.rbs +54 -30
- data/sig/steep/type_construction.rbs +85 -27
- data/sig/steep/type_inference/method_call.rbs +1 -1
- data/smoke/diagnostics-rbs/inherit-module.rbs +2 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
- data/steep.gemspec +1 -1
- metadata +16 -6
data/lib/steep/source.rb
CHANGED
@@ -1,27 +1,11 @@
|
|
1
1
|
module Steep
|
2
2
|
class Source
|
3
|
-
class LocatedAnnotation
|
4
|
-
attr_reader :line
|
5
|
-
attr_reader :annotation
|
6
|
-
attr_reader :source
|
7
|
-
|
8
|
-
def initialize(line:, source:, annotation:)
|
9
|
-
@line = line
|
10
|
-
@source = source
|
11
|
-
@annotation = annotation
|
12
|
-
end
|
13
|
-
|
14
|
-
def ==(other)
|
15
|
-
other.is_a?(LocatedAnnotation) &&
|
16
|
-
other.line == line &&
|
17
|
-
other.annotation == annotation
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
3
|
attr_reader :path
|
22
4
|
attr_reader :node
|
23
5
|
attr_reader :mapping
|
24
6
|
|
7
|
+
extend NodeHelper
|
8
|
+
|
25
9
|
def initialize(path:, node:, mapping:)
|
26
10
|
@path = path
|
27
11
|
@node = node
|
@@ -47,46 +31,61 @@ module Steep
|
|
47
31
|
|
48
32
|
def self.parse(source_code, path:, factory:)
|
49
33
|
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
|
50
|
-
node = new_parser().
|
34
|
+
node, comments = new_parser().parse_with_comments(buffer)
|
51
35
|
|
36
|
+
# @type var annotations: Array[AST::Annotation::t]
|
52
37
|
annotations = []
|
53
|
-
|
54
|
-
|
55
|
-
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
|
56
|
-
new_parser().tokenize(buffer)
|
57
|
-
end
|
38
|
+
# @type var type_comments: Hash[Integer, type_comment]
|
39
|
+
type_comments = {}
|
58
40
|
|
59
41
|
buffer = RBS::Buffer.new(name: path, content: source_code)
|
42
|
+
annotation_parser = AnnotationParser.new(factory: factory)
|
60
43
|
|
61
44
|
comments.each do |comment|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
45
|
+
if comment.inline?
|
46
|
+
content = comment.text.delete_prefix('#')
|
47
|
+
content.lstrip!
|
48
|
+
prefix = comment.text.size - content.size
|
49
|
+
content.rstrip!
|
50
|
+
suffix = comment.text.size - content.size - prefix
|
51
|
+
|
52
|
+
location = RBS::Location.new(
|
53
|
+
buffer: buffer,
|
54
|
+
start_pos: comment.location.expression.begin_pos + prefix,
|
55
|
+
end_pos: comment.location.expression.end_pos - suffix
|
56
|
+
)
|
57
|
+
|
58
|
+
case
|
59
|
+
when annotation = annotation_parser.parse(content, location: location)
|
60
|
+
annotations << annotation
|
61
|
+
when assertion = AST::Node::TypeAssertion.parse(location)
|
62
|
+
type_comments[assertion.line] = assertion
|
63
|
+
when tapp = AST::Node::TypeApplication.parse(location)
|
64
|
+
type_comments[tapp.line] = tapp
|
65
|
+
end
|
69
66
|
end
|
70
67
|
end
|
71
68
|
|
72
|
-
|
69
|
+
map = {}
|
70
|
+
map.compare_by_identity
|
73
71
|
|
74
72
|
if node
|
75
|
-
|
73
|
+
node = insert_type_node(node, type_comments)
|
74
|
+
construct_mapping(node: node, annotations: annotations, mapping: map)
|
76
75
|
end
|
77
76
|
|
78
77
|
annotations.each do |annot|
|
79
|
-
|
80
|
-
|
78
|
+
map[node] ||= []
|
79
|
+
map[node] << annot
|
81
80
|
end
|
82
81
|
|
83
|
-
new(path: path, node: node, mapping:
|
82
|
+
new(path: path, node: node, mapping: map)
|
84
83
|
end
|
85
84
|
|
86
85
|
def self.construct_mapping(node:, annotations:, mapping:, line_range: nil)
|
87
86
|
case node.type
|
88
87
|
when :if
|
89
|
-
if node.loc.
|
88
|
+
if node.loc.respond_to?(:question)
|
90
89
|
# Skip ternary operator
|
91
90
|
each_child_node node do |child|
|
92
91
|
construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
|
@@ -200,7 +199,7 @@ module Steep
|
|
200
199
|
last_cond = node.children[-2]
|
201
200
|
body = node.children.last
|
202
201
|
|
203
|
-
node.children.take(node.children.size-1) do |child|
|
202
|
+
node.children.take(node.children.size-1).each do |child|
|
204
203
|
construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
|
205
204
|
end
|
206
205
|
|
@@ -235,7 +234,7 @@ module Steep
|
|
235
234
|
end
|
236
235
|
end
|
237
236
|
|
238
|
-
associated_annotations = annotations.
|
237
|
+
associated_annotations, other_annotations = annotations.partition do |annot|
|
239
238
|
case node.type
|
240
239
|
when :def, :module, :class, :block, :ensure, :defs
|
241
240
|
loc = node.loc
|
@@ -257,33 +256,34 @@ module Steep
|
|
257
256
|
associated_annotations.each do |annot|
|
258
257
|
mapping[node] ||= []
|
259
258
|
mapping[node] << annot
|
260
|
-
annotations.delete annot
|
261
259
|
end
|
262
|
-
end
|
263
260
|
|
264
|
-
|
265
|
-
node.children.each do |child|
|
266
|
-
if child.is_a?(::AST::Node)
|
267
|
-
yield child
|
268
|
-
end
|
269
|
-
end
|
261
|
+
annotations.replace(other_annotations)
|
270
262
|
end
|
271
263
|
|
272
|
-
def self.
|
264
|
+
def self.map_child_node(node, type = nil, skip: nil)
|
273
265
|
children = node.children.map do |child|
|
274
|
-
if child.is_a?(::AST::Node)
|
275
|
-
|
266
|
+
if child.is_a?(Parser::AST::Node)
|
267
|
+
if skip
|
268
|
+
if skip.member?(child)
|
269
|
+
child
|
270
|
+
else
|
271
|
+
yield child
|
272
|
+
end
|
273
|
+
else
|
274
|
+
yield child
|
275
|
+
end
|
276
276
|
else
|
277
277
|
child
|
278
278
|
end
|
279
279
|
end
|
280
280
|
|
281
|
-
node.updated(
|
281
|
+
node.updated(type, children)
|
282
282
|
end
|
283
283
|
|
284
284
|
def annotations(block:, factory:, context:)
|
285
285
|
AST::Annotation::Collection.new(
|
286
|
-
annotations: (mapping[block] || [])
|
286
|
+
annotations: (mapping[block] || []),
|
287
287
|
factory: factory,
|
288
288
|
context: context
|
289
289
|
)
|
@@ -292,7 +292,7 @@ module Steep
|
|
292
292
|
def each_annotation(&block)
|
293
293
|
if block_given?
|
294
294
|
mapping.each do |node, annots|
|
295
|
-
yield node, annots
|
295
|
+
yield [node, annots]
|
296
296
|
end
|
297
297
|
else
|
298
298
|
enum_for :each_annotation
|
@@ -301,9 +301,11 @@ module Steep
|
|
301
301
|
|
302
302
|
def each_heredoc_node(node = self.node, parents = [], &block)
|
303
303
|
if block
|
304
|
+
return unless node
|
305
|
+
|
304
306
|
case node.type
|
305
307
|
when :dstr, :str
|
306
|
-
if node.location.
|
308
|
+
if node.location.respond_to?(:heredoc_body)
|
307
309
|
yield [node, *parents]
|
308
310
|
end
|
309
311
|
end
|
@@ -344,7 +346,9 @@ module Steep
|
|
344
346
|
parents.unshift node
|
345
347
|
|
346
348
|
Source.each_child_node(node) do |child|
|
347
|
-
ns = find_nodes_loc(child, position, parents)
|
349
|
+
if ns = find_nodes_loc(child, position, parents)
|
350
|
+
return ns
|
351
|
+
end
|
348
352
|
end
|
349
353
|
|
350
354
|
parents
|
@@ -359,12 +363,14 @@ module Steep
|
|
359
363
|
node.location.expression.source_buffer.source_line(i+1).size + 1
|
360
364
|
end + column
|
361
365
|
|
362
|
-
if
|
363
|
-
Source.each_child_node(
|
364
|
-
find_nodes_loc(child, position,
|
366
|
+
if heredoc_nodes = find_heredoc_nodes(line, column, position)
|
367
|
+
Source.each_child_node(heredoc_nodes[0]) do |child|
|
368
|
+
if nodes = find_nodes_loc(child, position, heredoc_nodes)
|
369
|
+
return nodes
|
370
|
+
end
|
365
371
|
end
|
366
372
|
|
367
|
-
|
373
|
+
return heredoc_nodes
|
368
374
|
else
|
369
375
|
find_nodes_loc(node, position, [])
|
370
376
|
end
|
@@ -385,7 +391,7 @@ module Steep
|
|
385
391
|
delete_defs(node.children[0], allow_list)
|
386
392
|
end
|
387
393
|
else
|
388
|
-
|
394
|
+
map_child_node(node) do |child|
|
389
395
|
delete_defs(child, allow_list)
|
390
396
|
end
|
391
397
|
end
|
@@ -398,7 +404,9 @@ module Steep
|
|
398
404
|
|
399
405
|
node_ = Source.delete_defs(node, defs)
|
400
406
|
|
401
|
-
mapping
|
407
|
+
# @type var mapping: Hash[Parser::AST::Node, Array[AST::Annotation::t]]
|
408
|
+
mapping = {}
|
409
|
+
mapping.compare_by_identity
|
402
410
|
|
403
411
|
annotations = self.mapping.values.flatten
|
404
412
|
Source.construct_mapping(node: node_, annotations: annotations, mapping: mapping)
|
@@ -414,19 +422,129 @@ module Steep
|
|
414
422
|
end
|
415
423
|
end
|
416
424
|
|
417
|
-
def
|
418
|
-
|
419
|
-
|
420
|
-
node.
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
425
|
+
def self.insert_type_node(node, comments)
|
426
|
+
if node.location.expression
|
427
|
+
first_line = node.location.expression.first_line
|
428
|
+
last_line = node.location.expression.last_line
|
429
|
+
last_comment = comments[last_line]
|
430
|
+
|
431
|
+
if (first_line..last_line).none? {|l| comments.key?(l) }
|
432
|
+
return node
|
433
|
+
end
|
434
|
+
|
435
|
+
case
|
436
|
+
when last_comment.is_a?(AST::Node::TypeAssertion)
|
437
|
+
case node.type
|
438
|
+
when :lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn
|
439
|
+
# Skip
|
440
|
+
when :masgn
|
441
|
+
lhs, rhs = node.children
|
442
|
+
node = node.updated(nil, [lhs, insert_type_node(rhs, comments)])
|
443
|
+
return adjust_location(node)
|
444
|
+
when :return, :break, :next
|
445
|
+
# Skip
|
446
|
+
when :begin
|
447
|
+
if node.loc.begin
|
448
|
+
# paren
|
449
|
+
child_assertions = comments.except(last_line)
|
450
|
+
node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
|
451
|
+
node = adjust_location(node)
|
452
|
+
return assertion_node(node, last_comment)
|
453
|
+
end
|
454
|
+
else
|
455
|
+
child_assertions = comments.except(last_line)
|
456
|
+
node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
|
457
|
+
node = adjust_location(node)
|
458
|
+
return assertion_node(node, last_comment)
|
459
|
+
end
|
460
|
+
when selector_line = sendish_node?(node)
|
461
|
+
if (comment = comments[selector_line]).is_a?(AST::Node::TypeApplication)
|
462
|
+
child_assertions = comments.except(selector_line)
|
463
|
+
case node.type
|
464
|
+
when :block
|
465
|
+
send, *children = node.children
|
466
|
+
node = node.updated(
|
467
|
+
nil,
|
468
|
+
[
|
469
|
+
map_child_node(send) {|child| insert_type_node(child, child_assertions) },
|
470
|
+
*children.map {|child| insert_type_node(child, child_assertions) }
|
471
|
+
]
|
472
|
+
)
|
473
|
+
when :numblock
|
474
|
+
send, size, body = node.children
|
475
|
+
node = node.updated(
|
476
|
+
nil,
|
477
|
+
[
|
478
|
+
map_child_node(send) {|child| insert_type_node(child, child_assertions) },
|
479
|
+
size,
|
480
|
+
insert_type_node(body, child_assertions)
|
481
|
+
]
|
482
|
+
)
|
483
|
+
else
|
484
|
+
node = map_child_node(node) {|child| insert_type_node(child, child_assertions) }
|
485
|
+
end
|
486
|
+
node = adjust_location(node)
|
487
|
+
return type_application_node(node, comment)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
adjust_location(
|
493
|
+
map_child_node(node, nil) {|child| insert_type_node(child, comments) }
|
494
|
+
)
|
495
|
+
end
|
496
|
+
|
497
|
+
def self.sendish_node?(node)
|
498
|
+
send_node =
|
499
|
+
case node.type
|
500
|
+
when :send, :csend
|
501
|
+
node
|
502
|
+
when :block, :numblock
|
503
|
+
send = node.children[0]
|
504
|
+
case send.type
|
505
|
+
when :send, :csend
|
506
|
+
send
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
if send_node
|
511
|
+
if send_node.location.dot
|
512
|
+
send_node.location.selector.line
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
def self.adjust_location(node)
|
518
|
+
if end_pos = node.location.expression&.end_pos
|
519
|
+
if last_pos = each_child_node(node).map {|node| node.location.expression&.end_pos }.compact.max
|
520
|
+
if last_pos > end_pos
|
521
|
+
props = { location: node.location.with_expression(node.location.expression.with(end_pos: last_pos)) }
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
if props
|
527
|
+
node.updated(nil, nil, props)
|
427
528
|
else
|
428
529
|
node
|
429
530
|
end
|
430
531
|
end
|
532
|
+
|
533
|
+
def self.assertion_node(node, type)
|
534
|
+
map = Parser::Source::Map.new(node.location.expression.with(end_pos: type.location.end_pos))
|
535
|
+
Parser::AST::Node.new(:assertion, [node, type], { location: map })
|
536
|
+
end
|
537
|
+
|
538
|
+
def self.type_application_node(node, tapp)
|
539
|
+
if node.location.expression.end_pos > tapp.location.end_pos
|
540
|
+
map = Parser::Source::Map.new(node.location.expression)
|
541
|
+
else
|
542
|
+
map = Parser::Source::Map.new(node.location.expression.with(end_pos: tapp.location.end_pos))
|
543
|
+
end
|
544
|
+
|
545
|
+
node = Parser::AST::Node.new(:tapp, [node, tapp], { location: map })
|
546
|
+
tapp.set_node(node)
|
547
|
+
node
|
548
|
+
end
|
431
549
|
end
|
432
550
|
end
|