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,394 @@
1
+ module Steep
2
+ module Services
3
+ class TypeCheckService
4
+ attr_reader :project
5
+ attr_reader :signature_validation_diagnostics
6
+ attr_reader :source_files
7
+ attr_reader :signature_services
8
+
9
+ class SourceFile
10
+ attr_reader :path
11
+ attr_reader :target
12
+ attr_reader :content
13
+ attr_reader :node
14
+ attr_reader :typing
15
+ attr_reader :errors
16
+ attr_reader :ignores
17
+
18
+ def initialize(path:, node:, content:, typing:, ignores:, errors:)
19
+ @path = path
20
+ @node = node
21
+ @content = content
22
+ @typing = typing
23
+ @ignores = ignores
24
+ @errors = errors
25
+ end
26
+
27
+ def self.with_syntax_error(path:, content:, error:)
28
+ new(path: path, node: false, content: content, errors: [error], typing: nil, ignores: nil)
29
+ end
30
+
31
+ def self.with_typing(path:, content:, typing:, node:, ignores:)
32
+ new(path: path, node: node, content: content, errors: nil, typing: typing, ignores: ignores)
33
+ end
34
+
35
+ def self.no_data(path:, content:)
36
+ new(path: path, content: content, node: false, errors: nil, typing: nil, ignores: nil)
37
+ end
38
+
39
+ def update_content(content)
40
+ self.class.new(
41
+ path: path,
42
+ content: content,
43
+ node: node,
44
+ errors: errors,
45
+ typing: typing,
46
+ ignores: ignores
47
+ )
48
+ end
49
+
50
+ def diagnostics
51
+ case
52
+ when errors
53
+ errors
54
+ when typing && ignores
55
+ errors = [] #: Array[Diagnostic::Ruby::Base]
56
+
57
+ errors.concat(
58
+ typing.errors.delete_if do |diagnostic|
59
+ case diagnostic.location
60
+ when ::Parser::Source::Range
61
+ ignores.ignore?(diagnostic.location.first_line, diagnostic.location.last_line, diagnostic.diagnostic_code)
62
+ when RBS::Location
63
+ ignores.ignore?(diagnostic.location.start_line, diagnostic.location.end_line, diagnostic.diagnostic_code)
64
+ end
65
+ end
66
+ )
67
+
68
+ ignores.error_ignores.each do |ignore|
69
+ errors << Diagnostic::Ruby::InvalidIgnoreComment.new(comment: ignore.comment)
70
+ end
71
+
72
+ errors
73
+ else
74
+ []
75
+ end
76
+ end
77
+ end
78
+
79
+ def initialize(project:)
80
+ @project = project
81
+
82
+ @source_files = {}
83
+ @signature_services = project.targets.each.with_object({}) do |target, hash| #$ Hash[Symbol, SignatureService]
84
+ loader = Project::Target.construct_env_loader(options: target.options, project: project)
85
+ hash[target.name] = SignatureService.load_from(loader, implicitly_returns_nil: target.implicitly_returns_nil)
86
+ end
87
+ @signature_validation_diagnostics = project.targets.each.with_object({}) do |target, hash| #$ Hash[Symbol, Hash[Pathname, Array[Diagnostic::Signature::Base]]]
88
+ hash[target.name] = {}
89
+ end
90
+ end
91
+
92
+ def signature_diagnostics
93
+ # @type var signature_diagnostics: Hash[Pathname, Array[Diagnostic::Signature::Base]]
94
+ signature_diagnostics = {}
95
+
96
+ project.targets.each do |target|
97
+ service = signature_services.fetch(target.name)
98
+
99
+ service.each_rbs_path do |path|
100
+ signature_diagnostics[path] ||= []
101
+ end
102
+
103
+ case service.status
104
+ when SignatureService::SyntaxErrorStatus, SignatureService::AncestorErrorStatus
105
+ service.status.diagnostics.group_by {|diag| diag.location&.buffer&.name&.to_s }.each do |path_string, diagnostics|
106
+ if path_string
107
+ path = Pathname(path_string)
108
+ signature_diagnostics.fetch(path).push(*diagnostics)
109
+ end
110
+ end
111
+ when SignatureService::LoadedStatus
112
+ validation_diagnostics = signature_validation_diagnostics[target.name] || {}
113
+ validation_diagnostics.each do |path, diagnostics|
114
+ signature_diagnostics.fetch(path).push(*diagnostics)
115
+ end
116
+ end
117
+ end
118
+
119
+ signature_diagnostics
120
+ end
121
+
122
+ def has_diagnostics?
123
+ each_diagnostics.count > 0
124
+ end
125
+
126
+ def diagnostics
127
+ each_diagnostics.to_h
128
+ end
129
+
130
+ def each_diagnostics(&block)
131
+ if block
132
+ signature_diagnostics.each do |path, diagnostics|
133
+ yield [path, diagnostics]
134
+ end
135
+
136
+ source_files.each_value do |file|
137
+ yield [file.path, file.diagnostics]
138
+ end
139
+ else
140
+ enum_for :each_diagnostics
141
+ end
142
+ end
143
+
144
+ def update(changes:)
145
+ Steep.measure "#update_signature" do
146
+ update_signature(changes: changes)
147
+ end
148
+
149
+ Steep.measure "#update_sources" do
150
+ update_sources(changes: changes)
151
+ end
152
+ end
153
+
154
+ def validate_signature(path:, target:)
155
+ Steep.logger.tagged "#validate_signature(path=#{path})" do
156
+ Steep.measure "validation" do
157
+ service = signature_services.fetch(target.name)
158
+
159
+ raise "#{path} is not library nor signature of #{target.name}" unless target.possible_signature_file?(path) || service.env_rbs_paths.include?(path)
160
+
161
+ case service.status
162
+ when SignatureService::SyntaxErrorStatus
163
+ diagnostics = service.status.diagnostics.select do |diag|
164
+ diag.location or raise
165
+ Pathname(diag.location.buffer.name) == path &&
166
+ (diag.is_a?(Diagnostic::Signature::SyntaxError) || diag.is_a?(Diagnostic::Signature::UnexpectedError))
167
+ end
168
+
169
+ when SignatureService::AncestorErrorStatus
170
+ diagnostics = service.status.diagnostics.select do |diag|
171
+ diag.location or raise
172
+ Pathname(diag.location.buffer.name) == path
173
+ end
174
+
175
+ when SignatureService::LoadedStatus
176
+ validator = Signature::Validator.new(checker: service.current_subtyping || raise)
177
+ type_names = service.type_names(paths: Set[path], env: service.latest_env).to_set
178
+
179
+ unless type_names.empty?
180
+ Steep.measure2 "Validating #{type_names.size} types" do |sampler|
181
+ type_names.each do |type_name|
182
+ sampler.sample(type_name.to_s) do
183
+ case
184
+ when type_name.class?
185
+ validator.validate_one_class(type_name)
186
+ when type_name.interface?
187
+ validator.validate_one_interface(type_name)
188
+ when type_name.alias?
189
+ validator.validate_one_alias(type_name)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ const_decls = service.const_decls(paths: Set[path], env: service.latest_env)
197
+ unless const_decls.empty?
198
+ Steep.measure2 "Validating #{const_decls.size} constants" do |sampler|
199
+ const_decls.each do |name, entry|
200
+ sampler.sample(name.to_s) do
201
+ validator.validate_one_constant(name, entry)
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ global_decls = service.global_decls(paths: Set[path])
208
+ unless global_decls.empty?
209
+ Steep.measure2 "Validating #{global_decls.size} globals" do |sampler|
210
+ global_decls.each do |name, entry|
211
+ sampler.sample(name.to_s) do
212
+ validator.validate_one_global(name, entry)
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ diagnostics = validator.each_error.select do |error|
219
+ error.location or raise
220
+ Pathname(error.location.buffer.name) == path
221
+ end
222
+ end
223
+
224
+ signature_validation_diagnostics.fetch(target.name)[path] = diagnostics
225
+ end
226
+ end
227
+ end
228
+
229
+ def typecheck_source(path:, target:)
230
+ return unless target
231
+
232
+ Steep.logger.tagged "#typecheck_source(path=#{path})" do
233
+ Steep.measure "typecheck" do
234
+ signature_service = signature_services.fetch(target.name)
235
+ subtyping = signature_service.current_subtyping
236
+
237
+ if subtyping
238
+ text = source_files.fetch(path).content
239
+ file = type_check_file(target: target, subtyping: subtyping, path: path, text: text) { signature_service.latest_constant_resolver }
240
+ source_files[path] = file
241
+
242
+ file.diagnostics
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ def update_signature(changes:)
249
+ Steep.logger.tagged "#update_signature" do
250
+ signature_targets = {} #: Hash[Pathname, Project::Target]
251
+ changes.each do |path, changes|
252
+ target = project.targets.find { _1.possible_signature_file?(path) } or next
253
+ signature_targets[path] = target
254
+ end
255
+
256
+ project.targets.each do |target|
257
+ Steep.logger.tagged "#{target.name}" do
258
+ # Load signatures from all project targets but `#unreferenced` ones
259
+ target_changes = changes.select do |path, _|
260
+ signature_target = signature_targets.fetch(path, nil) or next
261
+ signature_target == target || !signature_target.unreferenced
262
+ end
263
+
264
+ unless target_changes.empty?
265
+ signature_services.fetch(target.name).update(target_changes)
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ def update_sources(changes:)
273
+ changes.each do |path, changes|
274
+ if source_file?(path)
275
+ file = source_files[path] || SourceFile.no_data(path: path, content: "")
276
+ content = changes.inject(file.content) {|text, change| change.apply_to(text) }
277
+ source_files[path] = file.update_content(content)
278
+ end
279
+ end
280
+ end
281
+
282
+ def type_check_file(target:, subtyping:, path:, text:)
283
+ Steep.logger.tagged "#type_check_file(#{path}@#{target.name})" do
284
+ source = Source.parse(text, path: path, factory: subtyping.factory)
285
+ typing = TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: yield, cursor: nil)
286
+ ignores = Source::IgnoreRanges.new(ignores: source.ignores)
287
+ SourceFile.with_typing(path: path, content: text, node: source.node, typing: typing, ignores: ignores)
288
+ end
289
+ rescue AnnotationParser::SyntaxError => exn
290
+ error = Diagnostic::Ruby::AnnotationSyntaxError.new(message: exn.message, location: exn.location)
291
+ SourceFile.with_syntax_error(path: path, content: text, error: error)
292
+ rescue ::Parser::SyntaxError => exn
293
+ error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: (_ = exn).diagnostic.location)
294
+ SourceFile.with_syntax_error(path: path, content: text, error: error)
295
+ rescue EncodingError => exn
296
+ SourceFile.no_data(path: path, content: "")
297
+ rescue RuntimeError => exn
298
+ Steep.log_error(exn)
299
+ SourceFile.no_data(path: path, content: text)
300
+ end
301
+
302
+ def self.type_check(source:, subtyping:, constant_resolver:, cursor:)
303
+ annotations = source.annotations(block: source.node, factory: subtyping.factory, context: nil)
304
+
305
+ case annotations.self_type
306
+ when AST::Types::Name::Instance
307
+ module_name = annotations.self_type.name
308
+ module_type = AST::Types::Name::Singleton.new(name: module_name)
309
+ instance_type = annotations.self_type
310
+ when AST::Types::Name::Singleton
311
+ module_name = annotations.self_type.name
312
+ module_type = annotations.self_type
313
+ instance_type = annotations.self_type
314
+ else
315
+ module_name = AST::Builtin::Object.module_name
316
+ module_type = AST::Builtin::Object.module_type
317
+ instance_type = AST::Builtin::Object.instance_type
318
+ end
319
+
320
+ definition = subtyping.factory.definition_builder.build_instance(module_name)
321
+
322
+ const_env = TypeInference::ConstantEnv.new(
323
+ factory: subtyping.factory,
324
+ context: nil,
325
+ resolver: constant_resolver
326
+ )
327
+ type_env = TypeInference::TypeEnv.new(const_env)
328
+ type_env = TypeInference::TypeEnvBuilder.new(
329
+ TypeInference::TypeEnvBuilder::Command::ImportConstantAnnotations.new(annotations),
330
+ TypeInference::TypeEnvBuilder::Command::ImportGlobalDeclarations.new(subtyping.factory),
331
+ TypeInference::TypeEnvBuilder::Command::ImportInstanceVariableDefinition.new(definition, subtyping.factory),
332
+ TypeInference::TypeEnvBuilder::Command::ImportInstanceVariableAnnotations.new(annotations),
333
+ TypeInference::TypeEnvBuilder::Command::ImportLocalVariableAnnotations.new(annotations)
334
+ ).build(type_env)
335
+
336
+ context = TypeInference::Context.new(
337
+ block_context: nil,
338
+ module_context: TypeInference::Context::ModuleContext.new(
339
+ instance_type: instance_type,
340
+ module_type: module_type,
341
+ implement_name: nil,
342
+ nesting: nil,
343
+ class_name: module_name,
344
+ instance_definition: subtyping.factory.definition_builder.build_instance(module_name),
345
+ module_definition: subtyping.factory.definition_builder.build_singleton(module_name)
346
+ ),
347
+ method_context: nil,
348
+ break_context: nil,
349
+ self_type: instance_type,
350
+ type_env: type_env,
351
+ call_context: TypeInference::MethodCall::TopLevelContext.new,
352
+ variable_context: TypeInference::Context::TypeVariableContext.empty
353
+ )
354
+
355
+ typing = Typing.new(source: source, root_context: context, cursor: cursor)
356
+
357
+ construction = TypeConstruction.new(
358
+ checker: subtyping,
359
+ annotations: annotations,
360
+ source: source,
361
+ context: context,
362
+ typing: typing
363
+ )
364
+
365
+ construction.synthesize(source.node) if source.node
366
+
367
+ typing
368
+ end
369
+
370
+ def source_file?(path)
371
+ source_files.key?(path) || (project.target_for_source_path(path) ? true : false)
372
+ end
373
+
374
+ def signature_file?(path)
375
+ relative_path = project.relative_path(path)
376
+ targets = signature_services.select {|_, sig| sig.files.key?(relative_path) || sig.env_rbs_paths.include?(path) }
377
+ unless targets.empty?
378
+ targets.keys
379
+ end
380
+ end
381
+
382
+ def app_signature_file?(path)
383
+ target_names = signature_services.select {|_, sig| sig.files.key?(path) }.keys
384
+ unless target_names.empty?
385
+ target_names
386
+ end
387
+ end
388
+
389
+ def lib_signature_file?(path)
390
+ signature_services.each_value.any? {|sig| sig.env_rbs_paths.include?(path) }
391
+ end
392
+ end
393
+ end
394
+ end
@@ -0,0 +1,236 @@
1
+ module Steep
2
+ module Services
3
+ class TypeNameCompletion
4
+ module Prefix
5
+ RawIdentPrefix = _ = Struct.new(:ident) do
6
+ # @implements RawIdentPrefix
7
+
8
+ def const_name?
9
+ ident.start_with?(/[A-Z]/)
10
+ end
11
+
12
+ def size
13
+ ident.length
14
+ end
15
+ end
16
+
17
+ NamespacedIdentPrefix = _ = Struct.new(:namespace, :ident, :size) do
18
+ # @implements NamespacedIdentPrefix
19
+
20
+ def const_name?
21
+ ident.start_with?(/[A-Z]/)
22
+ end
23
+ end
24
+
25
+ NamespacePrefix = _ = Struct.new(:namespace, :size)
26
+
27
+ def self.parse(buffer, line:, column:)
28
+ pos = buffer.loc_to_pos([line, column])
29
+ prefix = buffer.content[0...pos] or raise
30
+ prefix.reverse!
31
+
32
+ case prefix
33
+ when /\A((::\w+[A-Z])+(::)?)/
34
+ namespace = $1 or raise
35
+ NamespacePrefix.new(RBS::Namespace.parse(namespace.reverse), namespace.size)
36
+ when /\A::/
37
+ NamespacePrefix.new(RBS::Namespace.root, 2)
38
+ when /\A(\w*[A-Za-z_])((::\w+[A-Z])+(::)?)/
39
+ namespace = $1 or raise
40
+ identifier = $2 or raise
41
+ NamespacedIdentPrefix.new(RBS::Namespace.parse(identifier.reverse), namespace.reverse, namespace.size + identifier.size)
42
+ when /\A(\w*[A-Za-z_])::/
43
+ namespace = $1 or raise
44
+ NamespacedIdentPrefix.new(RBS::Namespace.root, namespace.reverse, namespace.size + 2)
45
+ when /\A(\w*[A-Za-z_])/
46
+ identifier = $1 or raise
47
+ RawIdentPrefix.new(identifier.reverse)
48
+ end
49
+ end
50
+ end
51
+
52
+ attr_reader :env, :context, :type_name_resolver, :map
53
+
54
+ def initialize(env:, context:, dirs:)
55
+ @env = env
56
+ @context = context
57
+
58
+ table = RBS::Environment::UseMap::Table.new()
59
+ table.known_types.merge(env.class_decls.keys)
60
+ table.known_types.merge(env.class_alias_decls.keys)
61
+ table.known_types.merge(env.type_alias_decls.keys)
62
+ table.known_types.merge(env.interface_decls.keys)
63
+ table.compute_children
64
+
65
+ @map = RBS::Environment::UseMap.new(table: table)
66
+ dirs.each do |dir|
67
+ dir.clauses.each do |clause|
68
+ @map.build_map(clause)
69
+ end
70
+ end
71
+
72
+ @type_name_resolver = RBS::Resolver::TypeNameResolver.new(env)
73
+ end
74
+
75
+ def each_outer_module(context = self.context, &block)
76
+ if block
77
+ if (parent, con = context)
78
+ namespace = each_outer_module(parent, &block)
79
+ case con
80
+ when false
81
+ namespace
82
+ when RBS::TypeName
83
+ ns = con.with_prefix(namespace).to_namespace
84
+ yield(ns)
85
+ ns
86
+ end
87
+ else
88
+ yield(RBS::Namespace.root)
89
+ RBS::Namespace.root
90
+ end
91
+ else
92
+ enum_for :each_outer_module
93
+ end
94
+ end
95
+
96
+ def each_type_name(&block)
97
+ if block
98
+ env = self.env
99
+
100
+ table = {} #: Hash[RBS::Namespace, Array[RBS::TypeName]]
101
+ env.class_decls.each_key do |type_name|
102
+ yield(type_name)
103
+ (table[type_name.namespace] ||= []) << type_name
104
+ end
105
+ env.type_alias_decls.each_key do |type_name|
106
+ yield(type_name)
107
+ (table[type_name.namespace] ||= []) << type_name
108
+ end
109
+ env.interface_decls.each_key do |type_name|
110
+ yield(type_name)
111
+ (table[type_name.namespace] ||= []) << type_name
112
+ end
113
+ env.class_alias_decls.each_key do |type_name|
114
+ yield(type_name)
115
+ (table[type_name.namespace] ||= []) << type_name
116
+ end
117
+
118
+ env.class_alias_decls.each_key do |alias_name|
119
+ normalized_name = env.normalize_module_name?(alias_name) or next
120
+ each_type_name_under(alias_name, normalized_name, table: table, &block)
121
+ end
122
+
123
+ resolve_pairs = [] #: Array[[RBS::TypeName, RBS::TypeName]]
124
+
125
+ map.instance_eval do
126
+ @map.each_key do |name|
127
+ relative_name = RBS::TypeName.new(name: name, namespace: RBS::Namespace.empty)
128
+ if absolute_name = resolve?(relative_name)
129
+ if env.type_name?(absolute_name)
130
+ # Yields only if the relative type name resolves to existing absolute type name
131
+ resolve_pairs << [relative_name, absolute_name]
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ resolve_pairs.each do |use_name, absolute_name|
138
+ yield use_name
139
+ each_type_name_under(use_name, absolute_name, table: table, &block)
140
+ end
141
+ else
142
+ enum_for :each_type_name
143
+ end
144
+ end
145
+
146
+ def each_type_name_under(module_name, normalized_name, table:, &block)
147
+ if children = table.fetch(normalized_name.to_namespace, nil)
148
+ module_namespace = module_name.to_namespace
149
+
150
+ children.each do |normalized_child_name|
151
+ child_name = RBS::TypeName.new(namespace: module_namespace, name: normalized_child_name.name)
152
+
153
+ yield child_name
154
+
155
+ if normalized_child_name.class?
156
+ each_type_name_under(child_name, env.normalize_module_name(normalized_child_name), table: table, &block)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def resolve_used_name(name)
163
+ return nil if name.absolute?
164
+
165
+ case
166
+ when resolved = map.resolve?(name)
167
+ resolved
168
+ when name.namespace.empty?
169
+ nil
170
+ else
171
+ if resolved_parent = resolve_used_name(name.namespace.to_type_name)
172
+ resolved_name = RBS::TypeName.new(namespace: resolved_parent.to_namespace, name: name.name)
173
+ if env.normalize_type_name?(resolved_name)
174
+ resolved_name
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ def resolve_name_in_context(name)
181
+ if resolved_name = resolve_used_name(name)
182
+ return [resolved_name, name]
183
+ end
184
+
185
+ name.absolute? or raise
186
+ normalized_name = env.normalize_type_name?(name) or raise "Cannot normalize given type name `#{name}`"
187
+
188
+ name.namespace.path.reverse_each.inject(RBS::TypeName.new(namespace: RBS::Namespace.empty, name: name.name)) do |relative_name, component|
189
+ if type_name_resolver.resolve(relative_name, context: context) == name
190
+ return [normalized_name, relative_name]
191
+ end
192
+
193
+ RBS::TypeName.new(
194
+ namespace: RBS::Namespace.new(path: [component, *relative_name.namespace.path], absolute: false),
195
+ name: name.name
196
+ )
197
+ end
198
+
199
+ if type_name_resolver.resolve(name.relative!, context: context) == name && !resolve_used_name(name.relative!)
200
+ [normalized_name, name.relative!]
201
+ else
202
+ [normalized_name, name]
203
+ end
204
+ end
205
+
206
+ def find_type_names(prefix)
207
+ case prefix
208
+ when Prefix::RawIdentPrefix
209
+ each_type_name.filter do |type_name|
210
+ type_name.split.any? {|sym| sym.to_s.downcase.include?(prefix.ident.downcase) }
211
+ end
212
+ when Prefix::NamespacedIdentPrefix
213
+ absolute_namespace =
214
+ if prefix.namespace.empty?
215
+ RBS::Namespace.root
216
+ else
217
+ type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
218
+ end
219
+
220
+ each_type_name.filter do|name|
221
+ name.namespace == absolute_namespace &&
222
+ name.name.to_s.downcase.include?(prefix.ident.downcase)
223
+ end
224
+ when Prefix::NamespacePrefix
225
+ absolute_namespace = type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
226
+ each_type_name.filter {|name| name.namespace == absolute_namespace }
227
+ else
228
+ # Returns all of the accessible type names from the context
229
+ namespaces = each_outer_module.to_set
230
+ # Relative type name means a *use*d type name
231
+ each_type_name.filter {|name| namespaces.include?(name.namespace) || !name.absolute? }
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end