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,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