steep 0.51.0 → 0.52.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ module Steep
2
+ module Services
3
+ module HoverProvider
4
+ class RBS
5
+ TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
6
+ ClassContent = Struct.new(:location, :decl, keyword_init: true)
7
+ InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
8
+
9
+ attr_reader :service
10
+
11
+ def initialize(service:)
12
+ @service = service
13
+ end
14
+
15
+ def project
16
+ service.project
17
+ end
18
+
19
+ def content_for(target:, path:, line:, column:)
20
+ service = self.service.signature_services[target.name]
21
+
22
+ _, decls = service.latest_env.buffers_decls.find do |buffer, _|
23
+ Pathname(buffer.name) == path
24
+ end
25
+
26
+ return if decls.nil?
27
+
28
+ loc_key, path = ::RBS::Locator.new(decls: decls).find2(line: line, column: column) || return
29
+ head, *tail = path
30
+
31
+ case head
32
+ when ::RBS::Types::Alias
33
+ alias_decl = service.latest_env.alias_decls[head.name]&.decl or raise
34
+
35
+ TypeAliasContent.new(
36
+ location: head.location,
37
+ decl: alias_decl
38
+ )
39
+ when ::RBS::Types::ClassInstance, ::RBS::Types::ClassSingleton
40
+ if loc_key == :name
41
+ env = service.latest_env
42
+ class_decl = env.class_decls[head.name]&.decls[0]&.decl or raise
43
+ location = head.location[:name]
44
+ ClassContent.new(
45
+ location: location,
46
+ decl: class_decl
47
+ )
48
+ end
49
+ when ::RBS::Types::Interface
50
+ env = service.latest_env
51
+ interface_decl = env.interface_decls[head.name]&.decl or raise
52
+ location = head.location[:name]
53
+
54
+ InterfaceContent.new(
55
+ location: location,
56
+ decl: interface_decl
57
+ )
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,168 @@
1
+ module Steep
2
+ module Services
3
+ module HoverProvider
4
+ class Ruby
5
+ TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
6
+ VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
7
+ MethodCallContent = Struct.new(:node, :method_call, :location, keyword_init: true)
8
+ DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true)
9
+ ConstantContent = Struct.new(:location, :full_name, :type, :decl, keyword_init: true) do
10
+ def comments
11
+ case
12
+ when class_or_module?
13
+ decl.decls.filter_map {|d| d.decl.comment }
14
+ when constant?
15
+ [decl.decl.comment]
16
+ else
17
+ []
18
+ end.compact
19
+ end
20
+
21
+ def constant?
22
+ decl.is_a?(::RBS::Environment::SingleEntry)
23
+ end
24
+
25
+ def class_or_module?
26
+ decl.is_a?(::RBS::Environment::MultiEntry)
27
+ end
28
+ end
29
+
30
+ attr_reader :service
31
+
32
+ def initialize(service:)
33
+ @service = service
34
+ end
35
+
36
+ def project
37
+ service.project
38
+ end
39
+
40
+ def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
41
+ case
42
+ when instance_method
43
+ factory.definition_builder.build_instance(type_name).methods[instance_method]
44
+ when singleton_method
45
+ methods = factory.definition_builder.build_singleton(type_name).methods
46
+
47
+ if singleton_method == :new
48
+ methods[:new] || methods[:initialize]
49
+ else
50
+ methods[singleton_method]
51
+ end
52
+ end
53
+ end
54
+
55
+ def typecheck(target, path:, content:, line:, column:)
56
+ subtyping = service.signature_services[target.name].current_subtyping or return
57
+ source = Source.parse(content, path: path, factory: subtyping.factory)
58
+ source = source.without_unrelated_defs(line: line, column: column)
59
+ Services::TypeCheckService.type_check(source: source, subtyping: subtyping)
60
+ rescue
61
+ nil
62
+ end
63
+
64
+ def method_name_from_method(context, builder:)
65
+ defined_in = context.method.defined_in
66
+ method_name = context.name
67
+
68
+ case
69
+ when defined_in.class?
70
+ case
71
+ when builder.build_instance(defined_in).methods.key?(method_name)
72
+ InstanceMethodName.new(type_name: defined_in, method_name: method_name)
73
+ when builder.build_singleton(defined_in).methods.key?(method_name)
74
+ SingletonMethodName.new(type_name: defined_in, method_name: method_name)
75
+ end
76
+ else
77
+ InstanceMethodName.new(type_name: defined_in, method_name: method_name)
78
+ end
79
+ end
80
+
81
+ def content_for(target:, path:, line:, column:)
82
+ file = service.source_files[path]
83
+ typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
84
+ node, *parents = typing.source.find_nodes(line: line, column: column)
85
+
86
+ if node
87
+ case node.type
88
+ when :lvar
89
+ var_name = node.children[0]
90
+ context = typing.context_at(line: line, column: column)
91
+ var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
92
+
93
+ return VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
94
+
95
+ when :lvasgn
96
+ var_name, rhs = node.children
97
+ context = typing.context_at(line: line, column: column)
98
+ type = context.lvar_env[var_name] || typing.type_of(node: rhs)
99
+
100
+ return VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
101
+
102
+ when :send, :csend
103
+ result_node =
104
+ case parents[0]&.type
105
+ when :block, :numblock
106
+ if node == parents[0].children[0]
107
+ parents[0]
108
+ else
109
+ node
110
+ end
111
+ else
112
+ node
113
+ end
114
+
115
+ case call = typing.call_of(node: result_node)
116
+ when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
117
+ unless call.method_decls.empty?
118
+ return MethodCallContent.new(
119
+ node: result_node,
120
+ method_call: call,
121
+ location: node.location.selector
122
+ )
123
+ end
124
+ end
125
+
126
+ when :def, :defs
127
+ context = typing.context_at(line: line, column: column)
128
+ method_context = context.method_context
129
+
130
+ if method_context && method_context.method
131
+ return DefinitionContent.new(
132
+ node: node,
133
+ method_name: method_name_from_method(method_context, builder: context.factory.definition_builder),
134
+ method_type: method_context.method_type,
135
+ definition: method_context.method,
136
+ location: node.loc.name
137
+ )
138
+ end
139
+
140
+ when :const, :casgn
141
+ context = typing.context_at(line: line, column: column)
142
+
143
+ type = typing.type_of(node: node)
144
+ const_name = typing.source_index.reference(constant_node: node)
145
+
146
+ if const_name
147
+ decl = context.env.class_decls[const_name] || context.env.constant_decls[const_name]
148
+
149
+ return ConstantContent.new(
150
+ location: node.location.name,
151
+ full_name: const_name,
152
+ type: type,
153
+ decl: decl
154
+ )
155
+ end
156
+ end
157
+
158
+ TypeContent.new(
159
+ node: node,
160
+ type: typing.type_of(node: node),
161
+ location: node.location.expression
162
+ )
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,21 @@
1
+ module Steep
2
+ module Services
3
+ module HoverProvider
4
+ module SingletonMethods
5
+ def content_for(service:, path:, line:, column:)
6
+ project = service.project
7
+ target_for_code, targets_for_sigs = project.targets_for_path(path)
8
+
9
+ case
10
+ when target_for_code
11
+ Ruby.new(service: service).content_for(target: target_for_code, path: path, line: line, column: column)
12
+ when target = targets_for_sigs.first
13
+ RBS.new(service: service).content_for(target: target, path: path, line: line, column: column)
14
+ end
15
+ end
16
+ end
17
+
18
+ extend SingletonMethods
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # Steep runs on Ruby 2.6 and it needs a shim of `filter_map`
2
+
3
+ module Shims
4
+ module EnumerableFilterMap
5
+ def filter_map(&block)
6
+ if block
7
+ result = []
8
+
9
+ each do |element|
10
+ if value = yield(element)
11
+ result << value
12
+ end
13
+ end
14
+
15
+ result
16
+ else
17
+ enum_for :filter_map
18
+ end
19
+ end
20
+ end
21
+
22
+ unless Enumerable.method_defined?(:filter_map)
23
+ Enumerable.include EnumerableFilterMap
24
+
25
+ module ::Enumerable
26
+ alias filter_map filter_map
27
+ end
28
+ end
29
+ end
30
+
data/lib/steep/source.rb CHANGED
@@ -301,13 +301,42 @@ module Steep
301
301
  end
302
302
  end
303
303
 
304
- def find_nodes(line:, column:, node: self.node, position: nil, parents: [])
305
- return [] unless node
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
306
312
 
307
- position ||= (line-1).times.sum do |i|
308
- node.location.expression.source_buffer.source_line(i+1).size + 1
309
- end + column
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
310
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)
311
340
  range = node.location.expression&.yield_self do |r|
312
341
  r.begin_pos..r.end_pos
313
342
  end
@@ -317,7 +346,7 @@ module Steep
317
346
  parents.unshift node
318
347
 
319
348
  Source.each_child_node(node) do |child|
320
- ns = find_nodes(line: line, column: column, node: child, position: position, parents: parents) and return ns
349
+ ns = find_nodes_loc(child, position, parents) and return ns
321
350
  end
322
351
 
323
352
  parents
@@ -325,6 +354,24 @@ module Steep
325
354
  end
326
355
  end
327
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
+
328
375
  def self.delete_defs(node, allow_list)
329
376
  case node.type
330
377
  when :def
@@ -347,7 +347,7 @@ module Steep
347
347
 
348
348
  when relation.super_type.is_a?(AST::Types::Union)
349
349
  Any(relation) do |result|
350
- relation.super_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : 1 }.each do |super_type|
350
+ relation.super_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : -Float::INFINITY }.each do |super_type|
351
351
  rel = Relation.new(sub_type: relation.sub_type, super_type: super_type)
352
352
  result.add(rel) do
353
353
  check_type(rel)
@@ -357,7 +357,7 @@ module Steep
357
357
 
358
358
  when relation.sub_type.is_a?(AST::Types::Intersection)
359
359
  Any(relation) do |result|
360
- relation.sub_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : 1 }.each do |sub_type|
360
+ relation.sub_type.types.sort_by {|ty| (path = hole_path(ty)) ? -path.size : -Float::INFINITY }.each do |sub_type|
361
361
  rel = Relation.new(sub_type: sub_type, super_type: relation.super_type)
362
362
  result.add(rel) do
363
363
  check_type(rel)
@@ -1498,13 +1498,18 @@ module Steep
1498
1498
  end
1499
1499
 
1500
1500
  if super_node
1501
- _, constr, super_name = constr.synthesize_constant(super_node, super_node.children[0], super_node.children[1]) do
1502
- typing.add_error(
1503
- Diagnostic::Ruby::UnknownConstant.new(node: super_node, name: super_node.children[1]).class!
1504
- )
1505
- end
1506
- if super_name
1507
- typing.source_index.add_reference(constant: super_name, ref: super_node)
1501
+ if super_node.type == :const
1502
+ _, constr, super_name = constr.synthesize_constant(super_node, super_node.children[0], super_node.children[1]) do
1503
+ typing.add_error(
1504
+ Diagnostic::Ruby::UnknownConstant.new(node: super_node, name: super_node.children[1]).class!
1505
+ )
1506
+ end
1507
+
1508
+ if super_name
1509
+ typing.source_index.add_reference(constant: super_name, ref: super_node)
1510
+ end
1511
+ else
1512
+ _, constr = synthesize(super_node, hint: nil, condition: false)
1508
1513
  end
1509
1514
  end
1510
1515
 
@@ -2731,6 +2736,14 @@ module Steep
2731
2736
 
2732
2737
  return [type, constr, name]
2733
2738
  end
2739
+ when AST::Types::Any
2740
+ # Couldn't detect the type of the parent constant
2741
+ # Skip reporting error for this node.
2742
+ if node
2743
+ _, constr = add_typing(node, type: parent_type)
2744
+ end
2745
+
2746
+ return [parent_type, constr, nil]
2734
2747
  end
2735
2748
  end
2736
2749
 
@@ -2744,6 +2757,10 @@ module Steep
2744
2757
  end
2745
2758
  end
2746
2759
 
2760
+ if node
2761
+ _, constr = add_typing(node, type: AST::Builtin.any_type)
2762
+ end
2763
+
2747
2764
  [AST::Builtin.any_type, constr, nil]
2748
2765
  end
2749
2766
  end
@@ -2898,6 +2915,11 @@ module Steep
2898
2915
  call = call.with_return_type(typing.type_of(node: arguments.last))
2899
2916
  end
2900
2917
  end
2918
+
2919
+ if node.type == :csend || ((node.type == :block || node.type == :numblock) && node.children[0].type == :csend)
2920
+ optional_type = AST::Types::Union.build(types: [call.return_type, AST::Builtin.nil_type])
2921
+ call = call.with_return_type(optional_type)
2922
+ end
2901
2923
  else
2902
2924
  error = Diagnostic::Ruby::UnresolvedOverloading.new(
2903
2925
  node: node,
@@ -3964,6 +3986,11 @@ module Steep
3964
3986
  end
3965
3987
 
3966
3988
  def try_convert(type, method)
3989
+ case type
3990
+ when AST::Types::Any, AST::Types::Bot, AST::Types::Top, AST::Types::Var
3991
+ return
3992
+ end
3993
+
3967
3994
  interface = checker.factory.interface(type, private: false)
3968
3995
  if entry = interface.methods[method]
3969
3996
  method_type = entry.method_types.find do |method_type|
@@ -171,6 +171,10 @@ module Steep
171
171
  )
172
172
  end
173
173
 
174
+ def factory
175
+ type_env.subtyping.factory
176
+ end
177
+
174
178
  def env
175
179
  type_env.subtyping.factory.env
176
180
  end
data/lib/steep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.51.0"
2
+ VERSION = "0.52.2"
3
3
  end
data/lib/steep.rb CHANGED
@@ -21,6 +21,8 @@ require "terminal-table"
21
21
 
22
22
  require "rbs"
23
23
 
24
+ require "steep/shims/filter_map"
25
+
24
26
  require "steep/equatable"
25
27
  require "steep/method_name"
26
28
  require "steep/ast/types/helper"
@@ -92,23 +94,26 @@ require "steep/index/rbs_index"
92
94
  require "steep/index/signature_symbol_provider"
93
95
  require "steep/index/source_index"
94
96
 
95
- require "steep/server/change_buffer"
96
- require "steep/server/base_worker"
97
- require "steep/server/worker_process"
98
- require "steep/server/interaction_worker"
99
- require "steep/server/type_check_worker"
100
- require "steep/server/master"
101
-
102
97
  require "steep/services/content_change"
103
98
  require "steep/services/path_assignment"
104
99
  require "steep/services/signature_service"
105
100
  require "steep/services/type_check_service"
106
- require "steep/services/hover_content"
101
+ require "steep/services/hover_provider/singleton_methods"
102
+ require "steep/services/hover_provider/ruby"
103
+ require "steep/services/hover_provider/rbs"
107
104
  require "steep/services/completion_provider"
108
105
  require "steep/services/stats_calculator"
109
106
  require "steep/services/file_loader"
110
107
  require "steep/services/goto_service"
111
108
 
109
+ require "steep/server/lsp_formatter"
110
+ require "steep/server/change_buffer"
111
+ require "steep/server/base_worker"
112
+ require "steep/server/worker_process"
113
+ require "steep/server/interaction_worker"
114
+ require "steep/server/type_check_worker"
115
+ require "steep/server/master"
116
+
112
117
  require "steep/project"
113
118
  require "steep/project/pattern"
114
119
  require "steep/project/options"
@@ -557,16 +557,6 @@
557
557
  severity: ERROR
558
558
  message: 'Cannot find the declaration of constant: `FOO`'
559
559
  code: Ruby::UnknownConstant
560
- - range:
561
- start:
562
- line: 4
563
- character: 7
564
- end:
565
- line: 4
566
- character: 10
567
- severity: ERROR
568
- message: 'Cannot find the declaration of constant: `BAR`'
569
- code: Ruby::UnknownConstant
570
560
  - range:
571
561
  start:
572
562
  line: 6
data/steep.gemspec CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
34
34
  spec.add_runtime_dependency "listen", "~> 3.0"
35
35
  spec.add_runtime_dependency "language_server-protocol", ">= 3.15", "< 4.0"
36
- spec.add_runtime_dependency "rbs", ">= 2.3.0"
36
+ spec.add_runtime_dependency "rbs", ">= 2.3.2"
37
37
  spec.add_runtime_dependency "parallel", ">= 1.0.0"
38
38
  spec.add_runtime_dependency "terminal-table", ">= 2", "< 4"
39
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.51.0
4
+ version: 0.52.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-01 00:00:00.000000000 Z
11
+ date: 2022-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -98,14 +98,14 @@ dependencies:
98
98
  requirements:
99
99
  - - ">="
100
100
  - !ruby/object:Gem::Version
101
- version: 2.3.0
101
+ version: 2.3.2
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
105
105
  requirements:
106
106
  - - ">="
107
107
  - !ruby/object:Gem::Version
108
- version: 2.3.0
108
+ version: 2.3.2
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: parallel
111
111
  requirement: !ruby/object:Gem::Requirement
@@ -233,6 +233,7 @@ files:
233
233
  - lib/steep/server/base_worker.rb
234
234
  - lib/steep/server/change_buffer.rb
235
235
  - lib/steep/server/interaction_worker.rb
236
+ - lib/steep/server/lsp_formatter.rb
236
237
  - lib/steep/server/master.rb
237
238
  - lib/steep/server/type_check_worker.rb
238
239
  - lib/steep/server/worker_process.rb
@@ -240,11 +241,14 @@ files:
240
241
  - lib/steep/services/content_change.rb
241
242
  - lib/steep/services/file_loader.rb
242
243
  - lib/steep/services/goto_service.rb
243
- - lib/steep/services/hover_content.rb
244
+ - lib/steep/services/hover_provider/rbs.rb
245
+ - lib/steep/services/hover_provider/ruby.rb
246
+ - lib/steep/services/hover_provider/singleton_methods.rb
244
247
  - lib/steep/services/path_assignment.rb
245
248
  - lib/steep/services/signature_service.rb
246
249
  - lib/steep/services/stats_calculator.rb
247
250
  - lib/steep/services/type_check_service.rb
251
+ - lib/steep/shims/filter_map.rb
248
252
  - lib/steep/signature/validator.rb
249
253
  - lib/steep/source.rb
250
254
  - lib/steep/subtyping/cache.rb