steep-activesupport-4 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) 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/Steepfile +68 -0
  9. data/bin/console +14 -0
  10. data/bin/generate-diagnostics-docs.rb +112 -0
  11. data/bin/mem_graph.rb +67 -0
  12. data/bin/mem_prof.rb +102 -0
  13. data/bin/output_rebaseline.rb +34 -0
  14. data/bin/output_test.rb +60 -0
  15. data/bin/rbs +20 -0
  16. data/bin/rbs-inline +19 -0
  17. data/bin/setup +9 -0
  18. data/bin/stackprof_test.rb +19 -0
  19. data/bin/steep +19 -0
  20. data/bin/steep-check.rb +251 -0
  21. data/bin/steep-prof +16 -0
  22. data/doc/narrowing.md +195 -0
  23. data/doc/shape.md +194 -0
  24. data/exe/steep +18 -0
  25. data/guides/README.md +5 -0
  26. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
  27. data/guides/src/getting-started/getting-started.md +163 -0
  28. data/guides/src/nil-optional/nil-optional.md +195 -0
  29. data/lib/steep/annotation_parser.rb +199 -0
  30. data/lib/steep/ast/annotation/collection.rb +172 -0
  31. data/lib/steep/ast/annotation.rb +137 -0
  32. data/lib/steep/ast/builtin.rb +104 -0
  33. data/lib/steep/ast/ignore.rb +148 -0
  34. data/lib/steep/ast/node/type_application.rb +88 -0
  35. data/lib/steep/ast/node/type_assertion.rb +81 -0
  36. data/lib/steep/ast/types/any.rb +35 -0
  37. data/lib/steep/ast/types/boolean.rb +45 -0
  38. data/lib/steep/ast/types/bot.rb +35 -0
  39. data/lib/steep/ast/types/class.rb +43 -0
  40. data/lib/steep/ast/types/factory.rb +557 -0
  41. data/lib/steep/ast/types/helper.rb +40 -0
  42. data/lib/steep/ast/types/instance.rb +42 -0
  43. data/lib/steep/ast/types/intersection.rb +93 -0
  44. data/lib/steep/ast/types/literal.rb +59 -0
  45. data/lib/steep/ast/types/logic.rb +84 -0
  46. data/lib/steep/ast/types/name.rb +128 -0
  47. data/lib/steep/ast/types/nil.rb +41 -0
  48. data/lib/steep/ast/types/proc.rb +117 -0
  49. data/lib/steep/ast/types/record.rb +79 -0
  50. data/lib/steep/ast/types/self.rb +43 -0
  51. data/lib/steep/ast/types/shared_instance.rb +11 -0
  52. data/lib/steep/ast/types/top.rb +35 -0
  53. data/lib/steep/ast/types/tuple.rb +60 -0
  54. data/lib/steep/ast/types/union.rb +97 -0
  55. data/lib/steep/ast/types/var.rb +65 -0
  56. data/lib/steep/ast/types/void.rb +35 -0
  57. data/lib/steep/cli.rb +401 -0
  58. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  59. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  60. data/lib/steep/diagnostic/helper.rb +18 -0
  61. data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
  62. data/lib/steep/diagnostic/result_printer2.rb +48 -0
  63. data/lib/steep/diagnostic/ruby.rb +1221 -0
  64. data/lib/steep/diagnostic/signature.rb +570 -0
  65. data/lib/steep/drivers/annotations.rb +52 -0
  66. data/lib/steep/drivers/check.rb +339 -0
  67. data/lib/steep/drivers/checkfile.rb +210 -0
  68. data/lib/steep/drivers/diagnostic_printer.rb +105 -0
  69. data/lib/steep/drivers/init.rb +66 -0
  70. data/lib/steep/drivers/langserver.rb +56 -0
  71. data/lib/steep/drivers/print_project.rb +113 -0
  72. data/lib/steep/drivers/stats.rb +203 -0
  73. data/lib/steep/drivers/utils/driver_helper.rb +143 -0
  74. data/lib/steep/drivers/utils/jobs_option.rb +26 -0
  75. data/lib/steep/drivers/vendor.rb +27 -0
  76. data/lib/steep/drivers/watch.rb +194 -0
  77. data/lib/steep/drivers/worker.rb +58 -0
  78. data/lib/steep/equatable.rb +23 -0
  79. data/lib/steep/expectations.rb +228 -0
  80. data/lib/steep/index/rbs_index.rb +350 -0
  81. data/lib/steep/index/signature_symbol_provider.rb +185 -0
  82. data/lib/steep/index/source_index.rb +167 -0
  83. data/lib/steep/interface/block.rb +103 -0
  84. data/lib/steep/interface/builder.rb +843 -0
  85. data/lib/steep/interface/function.rb +1090 -0
  86. data/lib/steep/interface/method_type.rb +330 -0
  87. data/lib/steep/interface/shape.rb +239 -0
  88. data/lib/steep/interface/substitution.rb +159 -0
  89. data/lib/steep/interface/type_param.rb +115 -0
  90. data/lib/steep/located_value.rb +20 -0
  91. data/lib/steep/method_name.rb +42 -0
  92. data/lib/steep/module_helper.rb +24 -0
  93. data/lib/steep/node_helper.rb +273 -0
  94. data/lib/steep/path_helper.rb +30 -0
  95. data/lib/steep/project/dsl.rb +268 -0
  96. data/lib/steep/project/group.rb +31 -0
  97. data/lib/steep/project/options.rb +63 -0
  98. data/lib/steep/project/pattern.rb +59 -0
  99. data/lib/steep/project/target.rb +92 -0
  100. data/lib/steep/project.rb +78 -0
  101. data/lib/steep/rake_task.rb +132 -0
  102. data/lib/steep/range_extension.rb +29 -0
  103. data/lib/steep/server/base_worker.rb +97 -0
  104. data/lib/steep/server/change_buffer.rb +73 -0
  105. data/lib/steep/server/custom_methods.rb +77 -0
  106. data/lib/steep/server/delay_queue.rb +45 -0
  107. data/lib/steep/server/interaction_worker.rb +492 -0
  108. data/lib/steep/server/lsp_formatter.rb +455 -0
  109. data/lib/steep/server/master.rb +912 -0
  110. data/lib/steep/server/target_group_files.rb +205 -0
  111. data/lib/steep/server/type_check_controller.rb +366 -0
  112. data/lib/steep/server/type_check_worker.rb +303 -0
  113. data/lib/steep/server/work_done_progress.rb +64 -0
  114. data/lib/steep/server/worker_process.rb +176 -0
  115. data/lib/steep/services/completion_provider.rb +802 -0
  116. data/lib/steep/services/content_change.rb +61 -0
  117. data/lib/steep/services/file_loader.rb +74 -0
  118. data/lib/steep/services/goto_service.rb +441 -0
  119. data/lib/steep/services/hover_provider/rbs.rb +88 -0
  120. data/lib/steep/services/hover_provider/ruby.rb +221 -0
  121. data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
  122. data/lib/steep/services/path_assignment.rb +46 -0
  123. data/lib/steep/services/signature_help_provider.rb +202 -0
  124. data/lib/steep/services/signature_service.rb +428 -0
  125. data/lib/steep/services/stats_calculator.rb +68 -0
  126. data/lib/steep/services/type_check_service.rb +394 -0
  127. data/lib/steep/services/type_name_completion.rb +236 -0
  128. data/lib/steep/signature/validator.rb +651 -0
  129. data/lib/steep/source/ignore_ranges.rb +69 -0
  130. data/lib/steep/source.rb +691 -0
  131. data/lib/steep/subtyping/cache.rb +30 -0
  132. data/lib/steep/subtyping/check.rb +1113 -0
  133. data/lib/steep/subtyping/constraints.rb +341 -0
  134. data/lib/steep/subtyping/relation.rb +101 -0
  135. data/lib/steep/subtyping/result.rb +324 -0
  136. data/lib/steep/subtyping/variable_variance.rb +89 -0
  137. data/lib/steep/test.rb +9 -0
  138. data/lib/steep/thread_waiter.rb +43 -0
  139. data/lib/steep/type_construction.rb +5183 -0
  140. data/lib/steep/type_inference/block_params.rb +416 -0
  141. data/lib/steep/type_inference/case_when.rb +303 -0
  142. data/lib/steep/type_inference/constant_env.rb +56 -0
  143. data/lib/steep/type_inference/context.rb +195 -0
  144. data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
  145. data/lib/steep/type_inference/method_call.rb +193 -0
  146. data/lib/steep/type_inference/method_params.rb +531 -0
  147. data/lib/steep/type_inference/multiple_assignment.rb +194 -0
  148. data/lib/steep/type_inference/send_args.rb +712 -0
  149. data/lib/steep/type_inference/type_env.rb +341 -0
  150. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  151. data/lib/steep/typing.rb +321 -0
  152. data/lib/steep/version.rb +3 -0
  153. data/lib/steep.rb +369 -0
  154. data/manual/annotations.md +181 -0
  155. data/manual/ignore.md +20 -0
  156. data/manual/ruby-diagnostics.md +1879 -0
  157. data/sample/Steepfile +22 -0
  158. data/sample/lib/conference.rb +49 -0
  159. data/sample/lib/length.rb +35 -0
  160. data/sample/sig/conference.rbs +42 -0
  161. data/sample/sig/generics.rbs +15 -0
  162. data/sample/sig/length.rbs +34 -0
  163. data/steep-activesupport-4.gemspec +55 -0
  164. metadata +437 -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