steep-relaxed 1.9.3.3

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 (165) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGELOG.md +1032 -0
  5. data/LICENSE +21 -0
  6. data/README.md +260 -0
  7. data/Rakefile +227 -0
  8. data/STDGEM_DEPENDENCIES.txt +59 -0
  9. data/Steepfile +68 -0
  10. data/bin/console +14 -0
  11. data/bin/generate-diagnostics-docs.rb +112 -0
  12. data/bin/mem_graph.rb +67 -0
  13. data/bin/mem_prof.rb +102 -0
  14. data/bin/output_rebaseline.rb +34 -0
  15. data/bin/output_test.rb +60 -0
  16. data/bin/rbs +20 -0
  17. data/bin/rbs-inline +19 -0
  18. data/bin/setup +9 -0
  19. data/bin/stackprof_test.rb +19 -0
  20. data/bin/steep +19 -0
  21. data/bin/steep-check.rb +251 -0
  22. data/bin/steep-prof +16 -0
  23. data/doc/narrowing.md +195 -0
  24. data/doc/shape.md +194 -0
  25. data/exe/steep +18 -0
  26. data/guides/README.md +5 -0
  27. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
  28. data/guides/src/getting-started/getting-started.md +163 -0
  29. data/guides/src/nil-optional/nil-optional.md +195 -0
  30. data/lib/steep/annotation_parser.rb +199 -0
  31. data/lib/steep/ast/annotation/collection.rb +172 -0
  32. data/lib/steep/ast/annotation.rb +137 -0
  33. data/lib/steep/ast/builtin.rb +104 -0
  34. data/lib/steep/ast/ignore.rb +148 -0
  35. data/lib/steep/ast/node/type_application.rb +88 -0
  36. data/lib/steep/ast/node/type_assertion.rb +81 -0
  37. data/lib/steep/ast/types/any.rb +35 -0
  38. data/lib/steep/ast/types/boolean.rb +45 -0
  39. data/lib/steep/ast/types/bot.rb +35 -0
  40. data/lib/steep/ast/types/class.rb +43 -0
  41. data/lib/steep/ast/types/factory.rb +557 -0
  42. data/lib/steep/ast/types/helper.rb +40 -0
  43. data/lib/steep/ast/types/instance.rb +42 -0
  44. data/lib/steep/ast/types/intersection.rb +93 -0
  45. data/lib/steep/ast/types/literal.rb +59 -0
  46. data/lib/steep/ast/types/logic.rb +84 -0
  47. data/lib/steep/ast/types/name.rb +128 -0
  48. data/lib/steep/ast/types/nil.rb +41 -0
  49. data/lib/steep/ast/types/proc.rb +117 -0
  50. data/lib/steep/ast/types/record.rb +79 -0
  51. data/lib/steep/ast/types/self.rb +43 -0
  52. data/lib/steep/ast/types/shared_instance.rb +11 -0
  53. data/lib/steep/ast/types/top.rb +35 -0
  54. data/lib/steep/ast/types/tuple.rb +60 -0
  55. data/lib/steep/ast/types/union.rb +97 -0
  56. data/lib/steep/ast/types/var.rb +65 -0
  57. data/lib/steep/ast/types/void.rb +35 -0
  58. data/lib/steep/cli.rb +401 -0
  59. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  60. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  61. data/lib/steep/diagnostic/helper.rb +18 -0
  62. data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
  63. data/lib/steep/diagnostic/result_printer2.rb +48 -0
  64. data/lib/steep/diagnostic/ruby.rb +1221 -0
  65. data/lib/steep/diagnostic/signature.rb +570 -0
  66. data/lib/steep/drivers/annotations.rb +52 -0
  67. data/lib/steep/drivers/check.rb +339 -0
  68. data/lib/steep/drivers/checkfile.rb +210 -0
  69. data/lib/steep/drivers/diagnostic_printer.rb +105 -0
  70. data/lib/steep/drivers/init.rb +66 -0
  71. data/lib/steep/drivers/langserver.rb +56 -0
  72. data/lib/steep/drivers/print_project.rb +113 -0
  73. data/lib/steep/drivers/stats.rb +203 -0
  74. data/lib/steep/drivers/utils/driver_helper.rb +143 -0
  75. data/lib/steep/drivers/utils/jobs_option.rb +26 -0
  76. data/lib/steep/drivers/vendor.rb +27 -0
  77. data/lib/steep/drivers/watch.rb +194 -0
  78. data/lib/steep/drivers/worker.rb +58 -0
  79. data/lib/steep/equatable.rb +23 -0
  80. data/lib/steep/expectations.rb +228 -0
  81. data/lib/steep/index/rbs_index.rb +350 -0
  82. data/lib/steep/index/signature_symbol_provider.rb +185 -0
  83. data/lib/steep/index/source_index.rb +167 -0
  84. data/lib/steep/interface/block.rb +103 -0
  85. data/lib/steep/interface/builder.rb +843 -0
  86. data/lib/steep/interface/function.rb +1090 -0
  87. data/lib/steep/interface/method_type.rb +330 -0
  88. data/lib/steep/interface/shape.rb +239 -0
  89. data/lib/steep/interface/substitution.rb +159 -0
  90. data/lib/steep/interface/type_param.rb +115 -0
  91. data/lib/steep/located_value.rb +20 -0
  92. data/lib/steep/method_name.rb +42 -0
  93. data/lib/steep/module_helper.rb +24 -0
  94. data/lib/steep/node_helper.rb +273 -0
  95. data/lib/steep/path_helper.rb +30 -0
  96. data/lib/steep/project/dsl.rb +268 -0
  97. data/lib/steep/project/group.rb +31 -0
  98. data/lib/steep/project/options.rb +63 -0
  99. data/lib/steep/project/pattern.rb +59 -0
  100. data/lib/steep/project/target.rb +92 -0
  101. data/lib/steep/project.rb +78 -0
  102. data/lib/steep/rake_task.rb +132 -0
  103. data/lib/steep/range_extension.rb +29 -0
  104. data/lib/steep/server/base_worker.rb +97 -0
  105. data/lib/steep/server/change_buffer.rb +73 -0
  106. data/lib/steep/server/custom_methods.rb +77 -0
  107. data/lib/steep/server/delay_queue.rb +45 -0
  108. data/lib/steep/server/interaction_worker.rb +492 -0
  109. data/lib/steep/server/lsp_formatter.rb +455 -0
  110. data/lib/steep/server/master.rb +922 -0
  111. data/lib/steep/server/target_group_files.rb +205 -0
  112. data/lib/steep/server/type_check_controller.rb +366 -0
  113. data/lib/steep/server/type_check_worker.rb +303 -0
  114. data/lib/steep/server/work_done_progress.rb +64 -0
  115. data/lib/steep/server/worker_process.rb +176 -0
  116. data/lib/steep/services/completion_provider.rb +802 -0
  117. data/lib/steep/services/content_change.rb +61 -0
  118. data/lib/steep/services/file_loader.rb +74 -0
  119. data/lib/steep/services/goto_service.rb +441 -0
  120. data/lib/steep/services/hover_provider/rbs.rb +88 -0
  121. data/lib/steep/services/hover_provider/ruby.rb +221 -0
  122. data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
  123. data/lib/steep/services/path_assignment.rb +46 -0
  124. data/lib/steep/services/signature_help_provider.rb +202 -0
  125. data/lib/steep/services/signature_service.rb +428 -0
  126. data/lib/steep/services/stats_calculator.rb +68 -0
  127. data/lib/steep/services/type_check_service.rb +394 -0
  128. data/lib/steep/services/type_name_completion.rb +236 -0
  129. data/lib/steep/signature/validator.rb +651 -0
  130. data/lib/steep/source/ignore_ranges.rb +69 -0
  131. data/lib/steep/source.rb +691 -0
  132. data/lib/steep/subtyping/cache.rb +30 -0
  133. data/lib/steep/subtyping/check.rb +1113 -0
  134. data/lib/steep/subtyping/constraints.rb +341 -0
  135. data/lib/steep/subtyping/relation.rb +101 -0
  136. data/lib/steep/subtyping/result.rb +324 -0
  137. data/lib/steep/subtyping/variable_variance.rb +89 -0
  138. data/lib/steep/test.rb +9 -0
  139. data/lib/steep/thread_waiter.rb +43 -0
  140. data/lib/steep/type_construction.rb +5183 -0
  141. data/lib/steep/type_inference/block_params.rb +416 -0
  142. data/lib/steep/type_inference/case_when.rb +303 -0
  143. data/lib/steep/type_inference/constant_env.rb +56 -0
  144. data/lib/steep/type_inference/context.rb +195 -0
  145. data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
  146. data/lib/steep/type_inference/method_call.rb +193 -0
  147. data/lib/steep/type_inference/method_params.rb +531 -0
  148. data/lib/steep/type_inference/multiple_assignment.rb +194 -0
  149. data/lib/steep/type_inference/send_args.rb +712 -0
  150. data/lib/steep/type_inference/type_env.rb +341 -0
  151. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  152. data/lib/steep/typing.rb +321 -0
  153. data/lib/steep/version.rb +3 -0
  154. data/lib/steep.rb +369 -0
  155. data/manual/annotations.md +181 -0
  156. data/manual/ignore.md +20 -0
  157. data/manual/ruby-diagnostics.md +1879 -0
  158. data/sample/Steepfile +22 -0
  159. data/sample/lib/conference.rb +49 -0
  160. data/sample/lib/length.rb +35 -0
  161. data/sample/sig/conference.rbs +42 -0
  162. data/sample/sig/generics.rbs +15 -0
  163. data/sample/sig/length.rbs +34 -0
  164. data/steep-relaxed.gemspec +56 -0
  165. metadata +340 -0
@@ -0,0 +1,61 @@
1
+ module Steep
2
+ module Services
3
+ class ContentChange
4
+ class Position
5
+ attr_reader :line, :column
6
+
7
+ def initialize(line:, column:)
8
+ @line = line
9
+ @column = column
10
+ end
11
+
12
+ def ==(other)
13
+ other.is_a?(Position) && other.line == line && other.column == column
14
+ end
15
+
16
+ alias eql? ==
17
+
18
+ def hash
19
+ self.class.hash ^ line ^ column
20
+ end
21
+ end
22
+
23
+ attr_reader :range, :text
24
+
25
+ def initialize(range: nil, text:)
26
+ @range = range
27
+ @text = text
28
+ end
29
+
30
+ def ==(other)
31
+ other.is_a?(ContentChange) && other.range == range && other.text == text
32
+ end
33
+
34
+ alias eql? ==
35
+
36
+ def hash
37
+ self.class.hash ^ range.hash ^ text.hash
38
+ end
39
+
40
+ def self.string(string)
41
+ new(text: string)
42
+ end
43
+
44
+ def apply_to(text)
45
+ if range
46
+ text = text.dup
47
+ start_pos, end_pos = range
48
+
49
+ buf = RBS::Buffer.new(name: :_, content: text)
50
+ start_pos = buf.loc_to_pos([start_pos.line, start_pos.column])
51
+ end_pos = buf.loc_to_pos([end_pos.line, end_pos.column])
52
+
53
+ text[start_pos...end_pos] = self.text
54
+ text
55
+ else
56
+ self.text
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,74 @@
1
+ module Steep
2
+ module Services
3
+ class FileLoader
4
+ attr_reader :base_dir
5
+
6
+ def initialize(base_dir:)
7
+ @base_dir = base_dir
8
+ end
9
+
10
+ def each_path_in_target(target, command_line_patterns = [], &block)
11
+ if block
12
+ done = Set[] #: Set[Pathname]
13
+
14
+ handler = -> (path) do
15
+ unless done.include?(path)
16
+ done << path
17
+ yield path
18
+ end
19
+ end
20
+
21
+ target.groups.each do |group|
22
+ each_path_in_patterns(group.source_pattern, command_line_patterns, &handler)
23
+ each_path_in_patterns(group.signature_pattern, &handler)
24
+ end
25
+
26
+ each_path_in_patterns(target.source_pattern, command_line_patterns, &handler)
27
+ each_path_in_patterns(target.signature_pattern, &handler)
28
+ else
29
+ enum_for :each_path_in_target, target, command_line_patterns
30
+ end
31
+ end
32
+
33
+ def each_path_in_patterns(pattern, commandline_patterns = [])
34
+ if block_given?
35
+ pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
36
+
37
+ pats.each do |path|
38
+ Pathname.glob((base_dir + path).to_s).each do |absolute_path|
39
+ if absolute_path.file?
40
+ relative_path = absolute_path.relative_path_from(base_dir)
41
+ if pattern =~ relative_path
42
+ yield relative_path
43
+ end
44
+ else
45
+ files = Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
46
+
47
+ files.sort.each do |source_path|
48
+ if source_path.file?
49
+ relative_path = source_path.relative_path_from(base_dir)
50
+ unless pattern.ignore?(relative_path)
51
+ yield relative_path
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ else
59
+ enum_for :each_path_in_patterns, pattern, commandline_patterns
60
+ end
61
+ end
62
+
63
+ def load_changes(pattern, command_line_patterns = [], changes:)
64
+ each_path_in_patterns(pattern, command_line_patterns) do |path|
65
+ unless changes.key?(path)
66
+ changes[path] = [ContentChange.string((base_dir + path).read)]
67
+ end
68
+ end
69
+
70
+ changes
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,441 @@
1
+ module Steep
2
+ module Services
3
+ class GotoService
4
+ include ModuleHelper
5
+
6
+ module SourceHelper
7
+ def from_ruby?
8
+ from == :ruby
9
+ end
10
+
11
+ def from_rbs?
12
+ from == :rbs
13
+ end
14
+ end
15
+
16
+ class ConstantQuery < Struct.new(:name, :from, keyword_init: true)
17
+ include SourceHelper
18
+ end
19
+ class MethodQuery < Struct.new(:name, :from, keyword_init: true)
20
+ include SourceHelper
21
+ end
22
+ class TypeNameQuery < Struct.new(:name, keyword_init: true)
23
+ end
24
+
25
+ attr_reader :type_check, :assignment
26
+
27
+ def initialize(type_check:, assignment:)
28
+ @type_check = type_check
29
+ @assignment = assignment
30
+ end
31
+
32
+ def project
33
+ type_check.project
34
+ end
35
+
36
+ def implementation(path:, line:, column:)
37
+ locations = [] #: Array[target_loc]
38
+
39
+ queries = query_at(path: path, line: line, column: column)
40
+ queries.uniq!
41
+
42
+ queries.each do |query|
43
+ case query
44
+ when ConstantQuery
45
+ constant_definition_in_ruby(query.name, locations: locations)
46
+ when MethodQuery
47
+ method_locations(query.name, locations: locations, in_ruby: true, in_rbs: false)
48
+ when TypeNameQuery
49
+ constant_definition_in_ruby(query.name, locations: locations)
50
+ end
51
+ end
52
+
53
+ locations.map { _1[1] }.uniq
54
+ end
55
+
56
+ def definition(path:, line:, column:)
57
+ locations = [] #: Array[target_loc]
58
+
59
+ queries = query_at(path: path, line: line, column: column)
60
+ queries.uniq!
61
+
62
+ queries.each do |query|
63
+ case query
64
+ when ConstantQuery
65
+ constant_definition_in_rbs(query.name, locations: locations) if query.from_ruby?
66
+ constant_definition_in_ruby(query.name, locations: locations) if query.from_rbs?
67
+ when MethodQuery
68
+ method_locations(
69
+ query.name,
70
+ locations: locations,
71
+ in_ruby: query.from_rbs?,
72
+ in_rbs: query.from_ruby?
73
+ )
74
+ when TypeNameQuery
75
+ type_name_locations(query.name, locations: locations)
76
+ end
77
+ end
78
+
79
+ # Drop un-assigned paths here.
80
+ # The path assignment makes sense only for `.rbs` files, because un-assigned `.rb` files are already skipped since they are not type checked.
81
+ #
82
+ locations.filter_map do |target, loc|
83
+ case loc
84
+ when RBS::Location
85
+ if assignment =~ [target, loc.name]
86
+ loc
87
+ end
88
+ else
89
+ loc
90
+ end
91
+ end.uniq
92
+ end
93
+
94
+ def type_definition(path:, line:, column:)
95
+ locations = [] #: Array[target_loc]
96
+
97
+ relative_path = project.relative_path(path)
98
+
99
+ target = type_check.project.target_for_path(relative_path) or return []
100
+ source = type_check.source_files.fetch(relative_path)
101
+ typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
102
+
103
+ typing or return []
104
+ signature or return []
105
+
106
+ node, *_parents = typing.source.find_nodes(line: line, column: column)
107
+ node or return []
108
+
109
+ type = typing.type_of(node: node)
110
+
111
+ subtyping = signature.current_subtyping or return []
112
+
113
+ each_type_name(type).uniq.each do |name|
114
+ type_name_locations(name, locations: locations)
115
+ end
116
+
117
+ locations.filter_map do |target, loc|
118
+ case loc
119
+ when RBS::Location
120
+ if assignment =~ [target, loc.name]
121
+ loc
122
+ end
123
+ else
124
+ loc
125
+ end
126
+ end.uniq
127
+ end
128
+
129
+ def each_type_name(type, &block)
130
+ if block
131
+ case type
132
+ when AST::Types::Name::Instance, AST::Types::Name::Alias, AST::Types::Name::Singleton, AST::Types::Name::Interface
133
+ yield type.name
134
+ when AST::Types::Literal
135
+ yield type.back_type.name
136
+ when AST::Types::Nil
137
+ yield RBS::TypeName.new(name: :NilClass, namespace: RBS::Namespace.root)
138
+ when AST::Types::Boolean
139
+ yield RBS::BuiltinNames::TrueClass.name
140
+ yield RBS::BuiltinNames::FalseClass.name
141
+ end
142
+
143
+ type.each_child do |child|
144
+ each_type_name(child, &block)
145
+ end
146
+ else
147
+ enum_for :each_type_name, type
148
+ end
149
+ end
150
+
151
+ def test_ast_location(loc, line:, column:)
152
+ return false if line < loc.line
153
+ return false if line == loc.line && column < loc.column
154
+ return false if loc.last_line < line
155
+ return false if line == loc.last_line && loc.last_column < column
156
+ true
157
+ end
158
+
159
+ def query_at(path:, line:, column:)
160
+ queries = [] #: Array[query]
161
+
162
+ relative_path = project.relative_path(path)
163
+
164
+ 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)
170
+
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
212
+
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
225
+ end
226
+ end
227
+ when target_names = type_check.signature_file?(path) #: Array[Symbol]
228
+ target_names.each do |target_name|
229
+ signature_service = type_check.signature_services[target_name] #: SignatureService
230
+
231
+ 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
234
+
235
+ locator = RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
236
+ last, nodes = locator.find2(line: line, column: column)
237
+
238
+ nodes or raise
239
+
240
+ case nodes[0]
241
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
242
+ if last == :name
243
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
244
+ end
245
+ when RBS::AST::Declarations::Constant
246
+ if last == :name
247
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
248
+ end
249
+ when RBS::AST::Members::MethodDefinition
250
+ if last == :name
251
+ parent_node = nodes[1] #: RBS::AST::Declarations::Class | RBS::AST::Declarations::Module | RBS::AST::Declarations::Interface
252
+ type_name = parent_node.name
253
+ method_name = nodes[0].name
254
+ if nodes[0].instance?
255
+ queries << MethodQuery.new(
256
+ name: InstanceMethodName.new(type_name: type_name, method_name: method_name),
257
+ from: :rbs
258
+ )
259
+ end
260
+ if nodes[0].singleton?
261
+ queries << MethodQuery.new(
262
+ name: SingletonMethodName.new(type_name: type_name, method_name: method_name),
263
+ from: :rbs
264
+ )
265
+ end
266
+ end
267
+ when RBS::AST::Members::Include, RBS::AST::Members::Extend, RBS::AST::Members::Prepend
268
+ if last == :name
269
+ queries << TypeNameQuery.new(name: nodes[0].name)
270
+ end
271
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Interface, RBS::Types::Alias
272
+ if last == :name
273
+ queries << TypeNameQuery.new(name: nodes[0].name)
274
+ end
275
+ when RBS::AST::Declarations::Class::Super, RBS::AST::Declarations::Module::Self
276
+ if last == :name
277
+ queries << TypeNameQuery.new(name: nodes[0].name)
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ queries
284
+ end
285
+
286
+ def type_check_path(target:, path:, content:, line:, column:)
287
+ signature_service = type_check.signature_services.fetch(target.name)
288
+ subtyping = signature_service.current_subtyping or return
289
+ source = Source.parse(content, path: path, factory: subtyping.factory)
290
+ source = source.without_unrelated_defs(line: line, column: column)
291
+ resolver = RBS::Resolver::ConstantResolver.new(builder: subtyping.factory.definition_builder)
292
+ loc = source.buffer.loc_to_pos([line, column])
293
+ [
294
+ Services::TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: resolver, cursor: loc),
295
+ signature_service
296
+ ]
297
+ rescue
298
+ nil
299
+ end
300
+
301
+ def constant_definition_in_rbs(name, locations:)
302
+ project.targets.each do |target|
303
+ signature = type_check.signature_services.fetch(target.name)
304
+ env = signature.latest_env #: RBS::Environment
305
+
306
+ case entry = env.constant_entry(name)
307
+ when RBS::Environment::ConstantEntry
308
+ if entry.decl.location
309
+ locations << [target, entry.decl.location[:name]]
310
+ end
311
+ 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]]
315
+ end
316
+ end
317
+ when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
318
+ if entry.decl.location
319
+ locations << [target, entry.decl.location[:new_name]]
320
+ end
321
+ end
322
+ end
323
+
324
+ locations
325
+ end
326
+
327
+ def constant_definition_in_ruby(name, locations:)
328
+ type_check.source_files.each do |path, source|
329
+ if typing = source.typing
330
+ target = project.target_for_source_path(path) or raise
331
+ entry = typing.source_index.entry(constant: name)
332
+ entry.definitions.each do |node|
333
+ case node.type
334
+ when :const
335
+ locations << [target, node.location.expression]
336
+ when :casgn
337
+ parent = node.children[0]
338
+ location =
339
+ if parent
340
+ parent.location.expression.join(node.location.name)
341
+ else
342
+ node.location.name
343
+ end
344
+ locations << [target, location]
345
+ end
346
+ end
347
+ end
348
+ end
349
+
350
+ locations
351
+ end
352
+
353
+ def method_locations(name, in_ruby:, in_rbs:, locations:)
354
+ if in_ruby
355
+ type_check.source_files.each do |path, source|
356
+ if typing = source.typing
357
+ target = project.target_for_source_path(path) or raise
358
+ entry = typing.source_index.entry(method: name)
359
+
360
+ if entry.definitions.empty?
361
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
362
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
363
+ entry = typing.source_index.entry(method: initialize)
364
+ end
365
+ end
366
+
367
+ entry.definitions.each do |node|
368
+ case node.type
369
+ when :def
370
+ locations << [target, node.location.name]
371
+ when :defs
372
+ locations << [target, node.location.name]
373
+ end
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+ if in_rbs
380
+ project.targets.each do |target|
381
+ signature = type_check.signature_services.fetch(target.name)
382
+ index = signature.latest_rbs_index
383
+
384
+ entry = index.entry(method_name: name)
385
+
386
+ if entry.declarations.empty?
387
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
388
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
389
+ entry = index.entry(method_name: initialize)
390
+ end
391
+ end
392
+
393
+ entry.declarations.each do |decl|
394
+ case decl
395
+ when RBS::AST::Members::MethodDefinition
396
+ if decl.location
397
+ locations << [target, decl.location[:name]]
398
+ end
399
+ when RBS::AST::Members::Alias
400
+ if decl.location
401
+ locations << [target, decl.location[:new_name]]
402
+ end
403
+ when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
404
+ if decl.location
405
+ locations << [target, decl.location[:name]]
406
+ end
407
+ end
408
+ end
409
+ end
410
+ end
411
+
412
+ locations
413
+ end
414
+
415
+ def type_name_locations(name, locations: [])
416
+ project.targets.each do |target|
417
+ signature = type_check.signature_services.fetch(target.name)
418
+ index = signature.latest_rbs_index
419
+
420
+ entry = index.entry(type_name: name)
421
+ entry.declarations.each do |decl|
422
+ case decl
423
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface, RBS::AST::Declarations::TypeAlias
424
+ if decl.location
425
+ locations << [target, decl.location[:name]]
426
+ end
427
+ when RBS::AST::Declarations::AliasDecl
428
+ if decl.location
429
+ locations << [target, decl.location[:new_name]]
430
+ end
431
+ else
432
+ raise
433
+ end
434
+ end
435
+ end
436
+
437
+ locations
438
+ end
439
+ end
440
+ end
441
+ end
@@ -0,0 +1,88 @@
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.fetch(target.name)
21
+
22
+ 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
25
+
26
+ locator = ::RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
27
+ loc_key, path = locator.find2(line: line, column: column) || return
28
+ head, *_tail = path
29
+
30
+ case head
31
+ when ::RBS::Types::Alias
32
+ content_for_type_name(head.name, env: env, location: head.location || raise)
33
+
34
+ when ::RBS::Types::ClassInstance, ::RBS::Types::ClassSingleton
35
+ if loc_key == :name
36
+ location = head.location&.[](:name) or raise
37
+ content_for_type_name(head.name, env: env, location: location)
38
+ end
39
+
40
+ when ::RBS::Types::Interface
41
+ location = head.location&.[](:name) or raise
42
+ content_for_type_name(head.name, env: env, location: location)
43
+
44
+ when ::RBS::AST::Declarations::ClassAlias, ::RBS::AST::Declarations::ModuleAlias
45
+ if loc_key == :old_name
46
+ location = head.location&.[](:old_name) or raise
47
+ content_for_type_name(head.old_name, env: env, location: location)
48
+ end
49
+
50
+ when ::RBS::AST::Directives::Use::SingleClause
51
+ if loc_key == :type_name
52
+ location = head.location&.[](:type_name) or raise
53
+ content_for_type_name(head.type_name.absolute!, env: env, location: location)
54
+ end
55
+
56
+ when ::RBS::AST::Directives::Use::WildcardClause
57
+ if loc_key == :namespace
58
+ location = head.location&.[](:namespace) or raise
59
+ content_for_type_name(head.namespace.to_type_name.absolute!, env: env, location: location)
60
+ end
61
+ end
62
+ end
63
+
64
+ def content_for_type_name(type_name, env:, location:)
65
+ case
66
+ when type_name.alias?
67
+ alias_decl = env.type_alias_decls[type_name]&.decl or return
68
+ TypeAliasContent.new(location: location, decl: alias_decl)
69
+ when type_name.interface?
70
+ interface_decl = env.interface_decls[type_name]&.decl or return
71
+ InterfaceContent.new(location: location, decl: interface_decl)
72
+ when type_name.class?
73
+ class_entry = env.module_class_entry(type_name) or return
74
+
75
+ case class_entry
76
+ when ::RBS::Environment::ClassEntry, ::RBS::Environment::ModuleEntry
77
+ class_decl = class_entry.primary.decl
78
+ when ::RBS::Environment::ClassAliasEntry, ::RBS::Environment::ModuleAliasEntry
79
+ class_decl = class_entry.decl
80
+ end
81
+
82
+ ClassContent.new(location: location, decl: class_decl)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end