steep 0.51.0 → 0.52.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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