steep 1.10.0 → 2.0.0

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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -1
  3. data/CLAUDE.md +114 -0
  4. data/README.md +1 -1
  5. data/Rakefile +15 -3
  6. data/Steepfile +13 -13
  7. data/lib/steep/annotation_parser.rb +5 -1
  8. data/lib/steep/annotations_helper.rb +12 -2
  9. data/lib/steep/ast/node/type_application.rb +22 -16
  10. data/lib/steep/ast/node/type_assertion.rb +7 -4
  11. data/lib/steep/ast/types/factory.rb +3 -2
  12. data/lib/steep/cli.rb +246 -2
  13. data/lib/steep/daemon/configuration.rb +19 -0
  14. data/lib/steep/daemon/server.rb +476 -0
  15. data/lib/steep/daemon.rb +201 -0
  16. data/lib/steep/diagnostic/ruby.rb +50 -8
  17. data/lib/steep/diagnostic/signature.rb +31 -8
  18. data/lib/steep/drivers/check.rb +301 -140
  19. data/lib/steep/drivers/print_project.rb +9 -10
  20. data/lib/steep/drivers/query.rb +102 -0
  21. data/lib/steep/drivers/start_server.rb +19 -0
  22. data/lib/steep/drivers/stop_server.rb +20 -0
  23. data/lib/steep/drivers/watch.rb +2 -2
  24. data/lib/steep/index/rbs_index.rb +38 -13
  25. data/lib/steep/index/signature_symbol_provider.rb +24 -3
  26. data/lib/steep/interface/builder.rb +48 -15
  27. data/lib/steep/interface/shape.rb +13 -5
  28. data/lib/steep/locator.rb +377 -0
  29. data/lib/steep/project/dsl.rb +26 -5
  30. data/lib/steep/project/group.rb +8 -2
  31. data/lib/steep/project/target.rb +16 -2
  32. data/lib/steep/project.rb +21 -2
  33. data/lib/steep/server/base_worker.rb +2 -2
  34. data/lib/steep/server/change_buffer.rb +2 -1
  35. data/lib/steep/server/custom_methods.rb +12 -0
  36. data/lib/steep/server/inline_source_change_detector.rb +94 -0
  37. data/lib/steep/server/interaction_worker.rb +51 -74
  38. data/lib/steep/server/lsp_formatter.rb +48 -12
  39. data/lib/steep/server/master.rb +100 -18
  40. data/lib/steep/server/target_group_files.rb +124 -151
  41. data/lib/steep/server/type_check_controller.rb +276 -123
  42. data/lib/steep/server/type_check_worker.rb +104 -3
  43. data/lib/steep/services/completion_provider/rbs.rb +74 -0
  44. data/lib/steep/services/completion_provider/ruby.rb +652 -0
  45. data/lib/steep/services/completion_provider/type_name.rb +243 -0
  46. data/lib/steep/services/completion_provider.rb +39 -662
  47. data/lib/steep/services/content_change.rb +14 -1
  48. data/lib/steep/services/file_loader.rb +4 -2
  49. data/lib/steep/services/goto_service.rb +271 -68
  50. data/lib/steep/services/hover_provider/content.rb +67 -0
  51. data/lib/steep/services/hover_provider/rbs.rb +8 -9
  52. data/lib/steep/services/hover_provider/ruby.rb +123 -64
  53. data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
  54. data/lib/steep/services/signature_service.rb +129 -54
  55. data/lib/steep/services/type_check_service.rb +72 -27
  56. data/lib/steep/signature/validator.rb +30 -18
  57. data/lib/steep/source/ignore_ranges.rb +14 -4
  58. data/lib/steep/source.rb +16 -2
  59. data/lib/steep/tagged_logging.rb +39 -0
  60. data/lib/steep/type_construction.rb +94 -21
  61. data/lib/steep/type_inference/block_params.rb +7 -7
  62. data/lib/steep/type_inference/context.rb +4 -2
  63. data/lib/steep/type_inference/logic_type_interpreter.rb +21 -3
  64. data/lib/steep/type_inference/method_call.rb +4 -0
  65. data/lib/steep/type_inference/type_env.rb +1 -1
  66. data/lib/steep/typing.rb +0 -2
  67. data/lib/steep/version.rb +1 -1
  68. data/lib/steep.rb +42 -32
  69. data/manual/ruby-diagnostics.md +67 -0
  70. data/sample/Steepfile +1 -0
  71. data/sample/lib/conference.rb +1 -0
  72. data/sample/lib/deprecated.rb +6 -0
  73. data/sample/lib/inline.rb +43 -0
  74. data/sample/sig/generics.rbs +3 -0
  75. data/steep.gemspec +4 -5
  76. metadata +26 -26
  77. data/lib/steep/services/type_name_completion.rb +0 -236
@@ -41,12 +41,25 @@ module Steep
41
41
  new(text: string)
42
42
  end
43
43
 
44
+ def self.from_lsp(changes)
45
+ changes.map do |change|
46
+ content_range =
47
+ if range = change[:range]
48
+ [
49
+ range[:start].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) },
50
+ end_pos = range[:end].yield_self {|pos| Services::ContentChange::Position.new(line: pos[:line] + 1, column: pos[:character]) }
51
+ ] #: range
52
+ end
53
+ Services::ContentChange.new(range: content_range, text: change[:text])
54
+ end
55
+ end
56
+
44
57
  def apply_to(text)
45
58
  if range
46
59
  text = text.dup
47
60
  start_pos, end_pos = range
48
61
 
49
- buf = RBS::Buffer.new(name: :_, content: text)
62
+ buf = RBS::Buffer.new(name: Pathname("_"), content: text)
50
63
  start_pos = buf.loc_to_pos([start_pos.line, start_pos.column])
51
64
  end_pos = buf.loc_to_pos([end_pos.line, end_pos.column])
52
65
 
@@ -20,10 +20,12 @@ module Steep
20
20
 
21
21
  target.groups.each do |group|
22
22
  each_path_in_patterns(group.source_pattern, command_line_patterns, &handler)
23
+ each_path_in_patterns(group.inline_source_pattern, command_line_patterns, &handler)
23
24
  each_path_in_patterns(group.signature_pattern, &handler)
24
25
  end
25
26
 
26
27
  each_path_in_patterns(target.source_pattern, command_line_patterns, &handler)
28
+ each_path_in_patterns(target.inline_source_pattern, command_line_patterns, &handler)
27
29
  each_path_in_patterns(target.signature_pattern, &handler)
28
30
  else
29
31
  enum_for :each_path_in_target, target, command_line_patterns
@@ -35,14 +37,14 @@ module Steep
35
37
  pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
36
38
 
37
39
  pats.each do |path|
38
- Pathname.glob((base_dir + path).to_s).each do |absolute_path|
40
+ Pathname(base_dir).glob(path.to_s).each do |absolute_path|
39
41
  if absolute_path.file?
40
42
  relative_path = absolute_path.relative_path_from(base_dir)
41
43
  if pattern =~ relative_path
42
44
  yield relative_path
43
45
  end
44
46
  else
45
- files = Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
47
+ files = Pathname(absolute_path).glob("**/*#{pattern.ext}")
46
48
 
47
49
  files.sort.each do |source_path|
48
50
  if source_path.file?
@@ -33,6 +33,126 @@ module Steep
33
33
  type_check.project
34
34
  end
35
35
 
36
+ # Parses a string representing a class/type/constant/method name into a query value.
37
+ #
38
+ # Supported formats:
39
+ #
40
+ # * `RBS::Location` -- type name (class, module, interface, type alias, class/module alias, or constant)
41
+ # * `::RBS::Location` -- type name, fully qualified
42
+ # * `RBS::Parser#parse_type` -- instance method
43
+ # * `RBS::Parser.parse_signature` -- singleton method
44
+ #
45
+ # Returns `nil` when the given string cannot be parsed as any of the above.
46
+ #
47
+ def self.parse_name(name_string)
48
+ return nil if name_string.nil? || name_string.empty?
49
+
50
+ if index = name_string.index("#")
51
+ type_part = name_string[0...index] or return nil
52
+ method_part = name_string[(index + 1)..] or return nil
53
+ return nil if type_part.empty? || method_part.empty?
54
+
55
+ type_name = parse_type_name(type_part) or return nil
56
+ InstanceMethodName.new(type_name: type_name, method_name: method_part.to_sym)
57
+ elsif index = find_singleton_method_dot(name_string)
58
+ type_part = name_string[0...index] or return nil
59
+ method_part = name_string[(index + 1)..] or return nil
60
+ return nil if type_part.empty? || method_part.empty?
61
+
62
+ type_name = parse_type_name(type_part) or return nil
63
+ SingletonMethodName.new(type_name: type_name, method_name: method_part.to_sym)
64
+ else
65
+ parse_type_name(name_string)
66
+ end
67
+ rescue RBS::ParsingError, StandardError
68
+ nil
69
+ end
70
+
71
+ # Finds the index of a `.` that separates a type from a singleton method name.
72
+ #
73
+ # Returns the index of the last `.` that is *not* followed by another `.` (to avoid
74
+ # matching the empty string) and that is not part of `::`. Returns `nil` if none is found.
75
+ #
76
+ def self.find_singleton_method_dot(string)
77
+ index = string.length - 1
78
+ while index > 0
79
+ char = string[index]
80
+ if char == "."
81
+ prev = string[index - 1]
82
+ if prev != "." && prev != ":"
83
+ return index
84
+ end
85
+ end
86
+ index -= 1
87
+ end
88
+ nil
89
+ end
90
+
91
+ def self.parse_type_name(string)
92
+ string = "::#{string}" unless string.start_with?("::")
93
+ RBS::TypeName.parse(string)
94
+ rescue RBS::ParsingError, StandardError
95
+ nil
96
+ end
97
+
98
+ # Returns array of locations that is a response to a *Query definition* request.
99
+ #
100
+ # Unlike `#definition`, this method takes a parsed name value instead of a source position.
101
+ # The caller is expected to parse the name via `.parse_name` before calling this method.
102
+ #
103
+ # Each returned entry is either an `RBS::Location` (for RBS declarations) or a
104
+ # `Parser::Source::Range` (for Ruby source locations).
105
+ #
106
+ def query_definition(name)
107
+ locations = [] #: Array[target_loc]
108
+
109
+ case name
110
+ when RBS::TypeName
111
+ # `constant_definition_in_rbs` covers classes, modules, class/module aliases,
112
+ # and plain constants (via `env.constant_entry`).
113
+ constant_definition_in_rbs(name, locations: locations)
114
+ constant_definition_in_ruby(name, locations: locations)
115
+ # Additional lookups for declarations that are not reachable via `env.constant_entry`.
116
+ interface_and_type_alias_locations(name, locations: locations)
117
+ when InstanceMethodName, SingletonMethodName
118
+ method_locations(name, in_ruby: true, in_rbs: true, locations: locations)
119
+ end
120
+
121
+ locations.filter_map do |target, loc|
122
+ case loc
123
+ when RBS::Location
124
+ if assignment =~ [target, loc.name]
125
+ loc
126
+ end
127
+ else
128
+ loc
129
+ end
130
+ end.uniq
131
+ end
132
+
133
+ def interface_and_type_alias_locations(name, locations:)
134
+ project.targets.each do |target|
135
+ signature = type_check.signature_services.fetch(target.name)
136
+ env = signature.latest_env
137
+
138
+ if entry = env.interface_decls[name]
139
+ decl = entry.decl
140
+ if loc = decl.location
141
+ locations << [target, loc[:name]]
142
+ end
143
+ end
144
+
145
+ if entry = env.type_alias_decls[name]
146
+ decl = entry.decl
147
+ if loc = decl.location
148
+ locations << [target, loc[:name]]
149
+ end
150
+ end
151
+ end
152
+
153
+ locations
154
+ end
155
+
36
156
  def implementation(path:, line:, column:)
37
157
  locations = [] #: Array[target_loc]
38
158
 
@@ -162,75 +282,46 @@ module Steep
162
282
  relative_path = project.relative_path(path)
163
283
 
164
284
  case
165
- when target = type_check.project.target_for_source_path(relative_path)
166
- source = type_check.source_files.fetch(relative_path, nil) or return []
167
- typing, _signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
168
- if typing
169
- node, *parents = typing.source.find_nodes(line: line, column: column)
285
+ when target = type_check.project.target_for_inline_source_path(relative_path)
286
+ signature = type_check.signature_services.fetch(target.name)
287
+ source = signature.latest_env.sources.find do
288
+ if _1.is_a?(::RBS::Source::Ruby)
289
+ _1.buffer.name == relative_path
290
+ end
291
+ end
170
292
 
171
- if node && parents
172
- case node.type
173
- when :const, :casgn
174
- named_location = (_ = node.location) #: Parser::AST::_NamedLocation
175
- if test_ast_location(named_location.name, line: line, column: column)
176
- if name = typing.source_index.reference(constant_node: node)
177
- queries << ConstantQuery.new(name: name, from: :ruby)
178
- end
179
- end
180
- when :def, :defs
181
- named_location = (_ = node.location) #: Parser::AST::_NamedLocation
182
- if test_ast_location(named_location.name, line: line, column: column)
183
- if method_context = typing.cursor_context.context&.method_context
184
- if method = method_context.method
185
- method.defs.each do |defn|
186
- singleton_method =
187
- case defn.member
188
- when RBS::AST::Members::MethodDefinition
189
- defn.member.singleton?
190
- when RBS::AST::Members::Attribute
191
- defn.member.kind == :singleton
192
- end
193
-
194
- name =
195
- if singleton_method
196
- SingletonMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
197
- else
198
- InstanceMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
199
- end
200
-
201
- queries << MethodQuery.new(name: name, from: :ruby)
202
- end
203
- end
204
- end
205
- end
206
- when :send
207
- location = (_ = node.location) #: Parser::AST::_SelectorLocation
208
- if test_ast_location(location.selector, line: line, column: column)
209
- if (parent = parents[0]) && parent.type == :block && parent.children[0] == node
210
- node = parents[0]
211
- end
293
+ if source.is_a?(::RBS::Source::Ruby)
294
+ locator = Locator::Inline.new(source)
295
+ result = locator.find(line, column)
212
296
 
213
- case call = typing.call_of(node: node)
214
- when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
215
- call.method_decls.each do |decl|
216
- queries << MethodQuery.new(name: decl.method_name, from: :ruby)
217
- end
218
- when TypeInference::MethodCall::Untyped
219
- # nop
220
- when TypeInference::MethodCall::NoMethodError
221
- # nop
222
- end
223
- end
224
- end
297
+ case result
298
+ when Locator::InlineTypeNameResult
299
+ queries << TypeNameQuery.new(name: result.type_name)
300
+ end
301
+ end
302
+
303
+ if queries.empty?
304
+ source = type_check.source_files.fetch(relative_path, nil) or return []
305
+ typing, signature, subtyping = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
306
+ if typing && signature && subtyping
307
+ queries.concat query_at_implementation(typing, subtyping, line: line, column: column)
225
308
  end
226
309
  end
310
+ when target = type_check.project.target_for_source_path(relative_path)
311
+ source = type_check.source_files.fetch(relative_path, nil) or return []
312
+ typing, _signature, subtyping = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
313
+ if typing && subtyping
314
+ queries.concat query_at_implementation(typing, subtyping, line: line, column: column)
315
+ end
227
316
  when target_names = type_check.signature_file?(path) #: Array[Symbol]
228
317
  target_names.each do |target_name|
229
318
  signature_service = type_check.signature_services[target_name] #: SignatureService
230
319
 
231
320
  env = signature_service.latest_env
232
- buffer = env.buffers.find {|buf| buf.name.to_s == relative_path.to_s } or raise
233
- (dirs, decls = env.signatures[buffer]) or raise
321
+ source = env.each_rbs_source.find {|src| src.buffer.name == relative_path } or raise
322
+ buffer = source.buffer
323
+ dirs = source.directives
324
+ decls = source.declarations
234
325
 
235
326
  locator = RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
236
327
  last, nodes = locator.find2(line: line, column: column)
@@ -283,6 +374,93 @@ module Steep
283
374
  queries
284
375
  end
285
376
 
377
+ def query_at_implementation(typing, subtyping, line:, column:)
378
+ queries = [] #: Array[query]
379
+
380
+ locator = Locator::Ruby.new(typing.source)
381
+ result = locator.find(line, column)
382
+
383
+ case result
384
+ when Locator::NodeResult
385
+ node = result.node
386
+ parents = result.parents
387
+
388
+ case node.type
389
+ when :const, :casgn
390
+ named_location = (_ = node.location) #: Parser::AST::_NamedLocation
391
+ if test_ast_location(named_location.name, line: line, column: column)
392
+ if name = typing.source_index.reference(constant_node: node)
393
+ queries << ConstantQuery.new(name: name, from: :ruby)
394
+ end
395
+ end
396
+ when :def, :defs
397
+ named_location = (_ = node.location) #: Parser::AST::_NamedLocation
398
+ if test_ast_location(named_location.name, line: line, column: column)
399
+ if method_context = typing.cursor_context.context&.method_context
400
+ if method = method_context.method
401
+ method.defs.each do |defn|
402
+ singleton_method =
403
+ case defn.member
404
+ when RBS::AST::Members::MethodDefinition
405
+ defn.member.singleton?
406
+ when RBS::AST::Members::Attribute
407
+ defn.member.kind == :singleton
408
+ end
409
+
410
+ name =
411
+ if singleton_method
412
+ SingletonMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
413
+ else
414
+ InstanceMethodName.new(type_name: defn.defined_in, method_name: method_context.name)
415
+ end
416
+
417
+ queries << MethodQuery.new(name: name, from: :ruby)
418
+ end
419
+ end
420
+ end
421
+ end
422
+ when :send
423
+ location = (_ = node.location) #: Parser::AST::_SelectorLocation
424
+ if test_ast_location(location.selector, line: line, column: column)
425
+ if (parent = parents[0]) && parent.type == :block && parent.children[0] === node
426
+ node = parents[0]
427
+ end
428
+
429
+ case call = typing.call_of(node: node)
430
+ when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
431
+ call.method_decls.each do |decl|
432
+ queries << MethodQuery.new(name: decl.method_name, from: :ruby)
433
+ end
434
+ when TypeInference::MethodCall::Untyped
435
+ # nop
436
+ when TypeInference::MethodCall::NoMethodError
437
+ # nop
438
+ end
439
+ end
440
+ end
441
+ when Locator::TypeAssertionResult
442
+ context = typing.cursor_context.context or raise
443
+ nesting = context.module_context.nesting
444
+ type_vars = context.variable_context.type_params.map(&:name)
445
+ pos = typing.source.buffer.loc_to_pos([line, column])
446
+
447
+ if pair = result.locate_type_name(pos, nesting, subtyping, type_vars)
448
+ queries << TypeNameQuery.new(name: pair[0])
449
+ end
450
+ when Locator::TypeApplicationResult
451
+ context = typing.cursor_context.context or raise
452
+ nesting = context.module_context.nesting
453
+ type_vars = context.variable_context.type_params.map(&:name)
454
+ pos = typing.source.buffer.loc_to_pos([line, column])
455
+
456
+ if pair = result.locate_type_name(pos, nesting, subtyping, type_vars)
457
+ queries << TypeNameQuery.new(name: pair[0])
458
+ end
459
+ end
460
+
461
+ queries
462
+ end
463
+
286
464
  def type_check_path(target:, path:, content:, line:, column:)
287
465
  signature_service = type_check.signature_services.fetch(target.name)
288
466
  subtyping = signature_service.current_subtyping or return
@@ -292,7 +470,8 @@ module Steep
292
470
  loc = source.buffer.loc_to_pos([line, column])
293
471
  [
294
472
  Services::TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver, cursor: loc),
295
- signature_service
473
+ signature_service,
474
+ subtyping
296
475
  ]
297
476
  rescue
298
477
  nil
@@ -305,18 +484,36 @@ module Steep
305
484
 
306
485
  case entry = env.constant_entry(name)
307
486
  when RBS::Environment::ConstantEntry
308
- if entry.decl.location
309
- locations << [target, entry.decl.location[:name]]
487
+ case decl = entry.decl
488
+ when RBS::AST::Declarations::Constant
489
+ if entry.decl.location
490
+ locations << [target, entry.decl.location[:name]]
491
+ end
492
+ when RBS::AST::Ruby::Declarations::ConstantDecl
493
+ locations << [target, entry.decl.name_location]
494
+ else
495
+ raise "Unknown declaration: #{entry.decl.inspect}"
310
496
  end
311
497
  when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
312
- entry.decls.each do |d|
313
- if d.decl.location
314
- locations << [target, d.decl.location[:name]]
498
+ entry.each_decl do |decl|
499
+ case decl
500
+ when RBS::AST::Declarations::Base
501
+ if decl.location
502
+ locations << [target, decl.location[:name]]
503
+ end
504
+ when RBS::AST::Ruby::Declarations::ClassDecl, RBS::AST::Ruby::Declarations::ModuleDecl
505
+ locations << [target, decl.name_location]
506
+ else
507
+ raise "Unknown declaration: #{decl.inspect}"
315
508
  end
316
509
  end
317
510
  when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
318
- if entry.decl.location
319
- locations << [target, entry.decl.location[:new_name]]
511
+ if entry.decl.is_a?(RBS::AST::Declarations::Base)
512
+ if entry.decl.location
513
+ locations << [target, entry.decl.location[:new_name]]
514
+ end
515
+ else
516
+ locations << [target, entry.decl.name_location]
320
517
  end
321
518
  end
322
519
  end
@@ -404,6 +601,8 @@ module Steep
404
601
  if decl.location
405
602
  locations << [target, decl.location[:name]]
406
603
  end
604
+ when RBS::AST::Ruby::Members::DefMember
605
+ locations << [target, decl.name_location]
407
606
  end
408
607
  end
409
608
  end
@@ -428,6 +627,10 @@ module Steep
428
627
  if decl.location
429
628
  locations << [target, decl.location[:new_name]]
430
629
  end
630
+ when RBS::AST::Ruby::Declarations::ClassDecl, RBS::AST::Ruby::Declarations::ModuleDecl
631
+ locations << [target, decl.name_location]
632
+ when RBS::AST::Ruby::Declarations::ClassModuleAliasDecl
633
+ locations << [target, decl.name_location]
431
634
  else
432
635
  raise
433
636
  end
@@ -0,0 +1,67 @@
1
+ module Steep
2
+ module Services
3
+ module HoverProvider
4
+ TypeContent = _ = Struct.new(:node, :type, :location, keyword_init: true)
5
+ VariableContent = _ = Struct.new(:node, :name, :type, :location, keyword_init: true)
6
+ TypeAssertionContent = _ = Struct.new(:node, :original_type, :asserted_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
+ # @implements ConstantContent
11
+
12
+ def comments
13
+ case
14
+ when decl = class_decl
15
+ decl.each_decl.map do |decl|
16
+ case decl
17
+ when ::RBS::AST::Declarations::Base
18
+ decl.comment
19
+ when ::RBS::AST::Ruby::Declarations::Base
20
+ nil
21
+ end
22
+
23
+ end
24
+ when decl = class_alias
25
+ [decl.decl.comment]
26
+ when decl = constant_decl
27
+ [decl.decl.comment]
28
+ else
29
+ raise
30
+ end.compact
31
+ end
32
+
33
+ def class_decl
34
+ case decl
35
+ when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
36
+ decl
37
+ end
38
+ end
39
+
40
+ def class_alias
41
+ case decl
42
+ when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
43
+ decl
44
+ end
45
+ end
46
+
47
+ def constant_decl
48
+ if decl.is_a?(::RBS::Environment::ConstantEntry)
49
+ decl
50
+ end
51
+ end
52
+
53
+ def constant?
54
+ constant_decl ? true : false
55
+ end
56
+
57
+ def class_or_module?
58
+ (class_decl || class_alias) ? true : false
59
+ end
60
+ end
61
+
62
+ TypeAliasContent = _ = Struct.new(:location, :decl, keyword_init: true)
63
+ ClassTypeContent = _ = Struct.new(:location, :decl, keyword_init: true)
64
+ InterfaceTypeContent = _ = Struct.new(:location, :decl, keyword_init: true)
65
+ end
66
+ end
67
+ end
@@ -1,11 +1,8 @@
1
1
  module Steep
2
2
  module Services
3
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
4
 
5
+ class RBS
9
6
  attr_reader :service
10
7
 
11
8
  def initialize(service:)
@@ -20,8 +17,10 @@ module Steep
20
17
  service = self.service.signature_services.fetch(target.name)
21
18
 
22
19
  env = service.latest_env
23
- buffer = env.buffers.find {|buf| buf.name.to_s == path.to_s } or return
24
- (dirs, decls = env.signatures[buffer]) or raise
20
+ source = env.each_rbs_source.find {|src| src.buffer.name == path } or return
21
+ buffer = source.buffer
22
+ dirs = source.directives
23
+ decls = source.declarations
25
24
 
26
25
  locator = ::RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
27
26
  loc_key, path = locator.find2(line: line, column: column) || return
@@ -68,18 +67,18 @@ module Steep
68
67
  TypeAliasContent.new(location: location, decl: alias_decl)
69
68
  when type_name.interface?
70
69
  interface_decl = env.interface_decls[type_name]&.decl or return
71
- InterfaceContent.new(location: location, decl: interface_decl)
70
+ InterfaceTypeContent.new(location: location, decl: interface_decl)
72
71
  when type_name.class?
73
72
  class_entry = env.module_class_entry(type_name) or return
74
73
 
75
74
  case class_entry
76
75
  when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
77
- class_decl = class_entry.primary.decl
76
+ class_decl = class_entry.primary_decl
78
77
  when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
79
78
  class_decl = class_entry.decl
80
79
  end
81
80
 
82
- ClassContent.new(location: location, decl: class_decl)
81
+ ClassTypeContent.new(location: location, decl: class_decl)
83
82
  end
84
83
  end
85
84
  end