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,428 @@
1
+ module Steep
2
+ module Services
3
+ class SignatureService
4
+ attr_reader :status
5
+
6
+ class SyntaxErrorStatus
7
+ attr_reader :files, :changed_paths, :diagnostics, :last_builder
8
+
9
+ def initialize(files:, changed_paths:, diagnostics:, last_builder:)
10
+ @files = files
11
+ @changed_paths = changed_paths
12
+ @diagnostics = diagnostics
13
+ @last_builder = last_builder
14
+ end
15
+
16
+ def rbs_index
17
+ @rbs_index ||= Index::RBSIndex.new().tap do |index|
18
+ builder = Index::RBSIndex::Builder.new(index: index)
19
+ builder.env(last_builder.env)
20
+ end
21
+ end
22
+
23
+ def constant_resolver
24
+ @constant_resolver ||= RBS::Resolver::ConstantResolver.new(builder: last_builder)
25
+ end
26
+ end
27
+
28
+ class AncestorErrorStatus
29
+ attr_reader :files, :changed_paths, :diagnostics, :last_builder
30
+
31
+ def initialize(files:, changed_paths:, diagnostics:, last_builder:)
32
+ @files = files
33
+ @changed_paths = changed_paths
34
+ @diagnostics = diagnostics
35
+ @last_builder = last_builder
36
+ end
37
+
38
+ def rbs_index
39
+ @rbs_index ||= Index::RBSIndex.new().tap do |index|
40
+ builder = Index::RBSIndex::Builder.new(index: index)
41
+ builder.env(last_builder.env)
42
+ end
43
+ end
44
+
45
+ def constant_resolver
46
+ @constant_resolver ||= RBS::Resolver::ConstantResolver.new(builder: last_builder)
47
+ end
48
+ end
49
+
50
+ class LoadedStatus
51
+ attr_reader :files, :builder, :implicitly_returns_nil
52
+
53
+ def initialize(files:, builder:, implicitly_returns_nil:)
54
+ @files = files
55
+ @builder = builder
56
+ @implicitly_returns_nil = implicitly_returns_nil
57
+ end
58
+
59
+ def subtyping
60
+ @subtyping ||= begin
61
+ factory = AST::Types::Factory.new(builder: builder)
62
+ interface_builder = Interface::Builder.new(factory, implicitly_returns_nil: implicitly_returns_nil)
63
+ Subtyping::Check.new(builder: interface_builder)
64
+ end
65
+ end
66
+
67
+ def rbs_index
68
+ @rbs_index ||= Index::RBSIndex.new().tap do |index|
69
+ builder = Index::RBSIndex::Builder.new(index: index)
70
+ builder.env(self.builder.env)
71
+ end
72
+ end
73
+
74
+ def constant_resolver
75
+ @constant_resolver ||= RBS::Resolver::ConstantResolver.new(builder: builder)
76
+ end
77
+ end
78
+
79
+ FileStatus = _ = Struct.new(:path, :content, :signature, keyword_init: true)
80
+
81
+ attr_reader :implicitly_returns_nil
82
+
83
+ def initialize(env:, implicitly_returns_nil:)
84
+ builder = RBS::DefinitionBuilder.new(env: env)
85
+ @status = LoadedStatus.new(builder: builder, files: {}, implicitly_returns_nil: implicitly_returns_nil)
86
+ @implicitly_returns_nil = implicitly_returns_nil
87
+ end
88
+
89
+ def self.load_from(loader, implicitly_returns_nil:)
90
+ env = RBS::Environment.from_loader(loader).resolve_type_names
91
+ new(env: env, implicitly_returns_nil: implicitly_returns_nil)
92
+ end
93
+
94
+ def env_rbs_paths
95
+ @env_rbs_paths ||= latest_env.buffers.each.with_object(Set[]) do |buffer, set|
96
+ set << Pathname(buffer.name)
97
+ end
98
+ end
99
+
100
+ def each_rbs_path(&block)
101
+ if block
102
+ env_rbs_paths.each do |path|
103
+ unless files.key?(path)
104
+ yield path
105
+ end
106
+ end
107
+
108
+ files.each_key(&block)
109
+ else
110
+ enum_for :each_rbs_path
111
+ end
112
+ end
113
+
114
+ def files
115
+ status.files
116
+ end
117
+
118
+ def pending_changed_paths
119
+ case status = status()
120
+ when LoadedStatus
121
+ Set[]
122
+ when SyntaxErrorStatus, AncestorErrorStatus
123
+ Set.new(status.changed_paths)
124
+ end
125
+ end
126
+
127
+ def latest_env
128
+ latest_builder.env
129
+ end
130
+
131
+ def latest_builder
132
+ case status = status()
133
+ when LoadedStatus
134
+ status.builder
135
+ when SyntaxErrorStatus, AncestorErrorStatus
136
+ status.last_builder
137
+ end
138
+ end
139
+
140
+ def latest_rbs_index
141
+ status.rbs_index
142
+ end
143
+
144
+ def latest_constant_resolver
145
+ status.constant_resolver
146
+ end
147
+
148
+ def current_subtyping
149
+ if status.is_a?(LoadedStatus)
150
+ status.subtyping
151
+ end
152
+ end
153
+
154
+ def apply_changes(files, changes)
155
+ Steep.logger.tagged "#apply_changes" do
156
+ Steep.measure2 "Applying change" do |sampler|
157
+ changes.each.with_object({}) do |pair, update| # $ Hash[Pathname, FileStatus]
158
+ path, cs = pair
159
+ sampler.sample "#{path}" do
160
+ old_text = files[path]&.content
161
+ content = cs.inject(old_text || "") {|text, change| change.apply_to(text) }
162
+
163
+ content ||= "" # It was not clear why `content` can be `nil`, but it happens with `master_test`.
164
+ buffer = RBS::Buffer.new(name: path, content: content)
165
+
166
+ update[path] =
167
+ begin
168
+ FileStatus.new(path: path, content: content, signature: RBS::Parser.parse_signature(buffer))
169
+ rescue ArgumentError => exn
170
+ error = Diagnostic::Signature::UnexpectedError.new(
171
+ message: exn.message,
172
+ location: RBS::Location.new(buffer: buffer, start_pos: 0, end_pos: content.size)
173
+ )
174
+ FileStatus.new(path: path, content: content, signature: error)
175
+ rescue RBS::ParsingError => exn
176
+ FileStatus.new(path: path, content: content, signature: exn)
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def update(changes)
185
+ Steep.logger.tagged "#update" do
186
+ updates = apply_changes(files, changes)
187
+ paths = Set.new(updates.each_key)
188
+ paths.merge(pending_changed_paths)
189
+
190
+ if updates.each_value.any? {|file| !file.signature.is_a?(Array) }
191
+ diagnostics = [] #: Array[Diagnostic::Signature::Base]
192
+
193
+ updates.each_value do |file|
194
+ unless file.signature.is_a?(Array)
195
+ diagnostic = if file.signature.is_a?(Diagnostic::Signature::Base)
196
+ file.signature
197
+ else
198
+ # factory is not used here because the error is a syntax error.
199
+ Diagnostic::Signature.from_rbs_error(file.signature, factory: _ = nil)
200
+ end
201
+ diagnostics << diagnostic
202
+ end
203
+ end
204
+
205
+ @status = SyntaxErrorStatus.new(
206
+ files: self.files.merge(updates),
207
+ diagnostics: diagnostics,
208
+ last_builder: latest_builder,
209
+ changed_paths: paths
210
+ )
211
+ else
212
+ files = self.files.merge(updates)
213
+ updated_files = files.slice(*paths.to_a)
214
+ result =
215
+ Steep.measure "#update_env with updated #{paths.size} files" do
216
+ update_env(updated_files, paths: paths)
217
+ end
218
+
219
+ @status = case result
220
+ when Array
221
+ AncestorErrorStatus.new(
222
+ changed_paths: paths,
223
+ last_builder: latest_builder,
224
+ diagnostics: result,
225
+ files: files
226
+ )
227
+ when RBS::DefinitionBuilder::AncestorBuilder
228
+ builder2 = update_builder(ancestor_builder: result, paths: paths)
229
+ LoadedStatus.new(builder: builder2, files: files, implicitly_returns_nil: implicitly_returns_nil)
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ def update_env(updated_files, paths:)
236
+ Steep.logger.tagged "#update_env" do
237
+ errors = [] #: Array[RBS::BaseError]
238
+ new_decls = Set[].compare_by_identity #: Set[RBS::AST::Declarations::t]
239
+
240
+ env =
241
+ Steep.measure "Deleting out of date decls" do
242
+ bufs = latest_env.buffers.select {|buf| paths.include?(buf.name) }
243
+ latest_env.unload(Set.new(bufs))
244
+ end
245
+
246
+ Steep.measure "Loading new decls" do
247
+ updated_files.each_value do |content|
248
+ case content.signature
249
+ when RBS::ParsingError
250
+ errors << content.signature
251
+ when Diagnostic::Signature::UnexpectedError
252
+ return [content.signature]
253
+ else
254
+ begin
255
+ buffer, dirs, decls = content.signature
256
+ env.add_signature(buffer: buffer, directives: dirs, decls: decls)
257
+ new_decls.merge(decls)
258
+ rescue RBS::LoadingError => exn
259
+ errors << exn
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ Steep.measure "validate type params" do
266
+ begin
267
+ env.validate_type_params
268
+ rescue RBS::LoadingError => exn
269
+ errors << exn
270
+ end
271
+ end
272
+
273
+ unless errors.empty?
274
+ return errors.map {|error|
275
+ # Factory will not be used because of the possible error types.
276
+ Diagnostic::Signature.from_rbs_error(error, factory: _ = nil)
277
+ }
278
+ end
279
+
280
+ Steep.measure "resolve type names with #{new_decls.size} top-level decls" do
281
+ env = env.resolve_type_names(only: new_decls)
282
+ end
283
+
284
+ builder = RBS::DefinitionBuilder::AncestorBuilder.new(env: env)
285
+
286
+ Steep.measure("Pre-loading one ancestors") do
287
+ builder.env.class_decls.each_key do |type_name|
288
+ rescue_rbs_error(errors) { builder.one_instance_ancestors(type_name) }
289
+ rescue_rbs_error(errors) { builder.one_singleton_ancestors(type_name) }
290
+ end
291
+ builder.env.interface_decls.each_key do |type_name|
292
+ rescue_rbs_error(errors) { builder.one_interface_ancestors(type_name) }
293
+ end
294
+ end
295
+
296
+ unless errors.empty?
297
+ # Builder won't be used.
298
+ factory = AST::Types::Factory.new(builder: _ = nil)
299
+ return errors.map {|error| Diagnostic::Signature.from_rbs_error(error, factory: factory) }
300
+ end
301
+
302
+ builder
303
+ end
304
+ end
305
+
306
+ def rescue_rbs_error(errors)
307
+ begin
308
+ yield
309
+ rescue RBS::BaseError => exn
310
+ errors << exn
311
+ end
312
+ end
313
+
314
+ def update_builder(ancestor_builder:, paths:)
315
+ Steep.measure "#update_builder with #{paths.size} files" do
316
+ changed_names = Set[]
317
+
318
+ old_definition_builder = latest_builder
319
+ old_env = old_definition_builder.env
320
+ old_names = type_names(paths: paths, env: old_env)
321
+ old_ancestor_builder = old_definition_builder.ancestor_builder
322
+ old_graph = RBS::AncestorGraph.new(env: old_env, ancestor_builder: old_ancestor_builder)
323
+ add_descendants(graph: old_graph, names: old_names, set: changed_names)
324
+ add_nested_decls(env: old_env, names: old_names, set: changed_names)
325
+
326
+ new_env = ancestor_builder.env
327
+ new_ancestor_builder = ancestor_builder
328
+ new_names = type_names(paths: paths, env: new_env)
329
+ new_graph = RBS::AncestorGraph.new(env: new_env, ancestor_builder: new_ancestor_builder)
330
+ add_descendants(graph: new_graph, names: new_names, set: changed_names)
331
+ add_nested_decls(env: new_env, names: new_names, set: changed_names)
332
+
333
+ old_definition_builder.update(
334
+ env: new_env,
335
+ ancestor_builder: new_ancestor_builder,
336
+ except: changed_names
337
+ )
338
+ end
339
+ end
340
+
341
+ def type_names(paths:, env:)
342
+ env.declarations.each.with_object(Set[]) do |decl, set|
343
+ if decl.location
344
+ if paths.include?(Pathname(decl.location.buffer.name))
345
+ type_name_from_decl(decl, set: set)
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ def const_decls(paths:, env:)
352
+ env.constant_decls.filter do |_, entry|
353
+ if location = entry.decl.location
354
+ paths.include?(Pathname(location.buffer.name))
355
+ end
356
+ end
357
+ end
358
+
359
+ def global_decls(paths:, env: latest_env)
360
+ env.global_decls.filter do |_, entry|
361
+ if location = entry.decl.location
362
+ paths.include?(Pathname(location.buffer.name))
363
+ end
364
+ end
365
+ end
366
+
367
+ def type_name_from_decl(decl, set:)
368
+ case decl
369
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
370
+ set << decl.name
371
+
372
+ decl.members.each do |member|
373
+ if member.is_a?(RBS::AST::Declarations::Base)
374
+ type_name_from_decl(member, set: set)
375
+ end
376
+ end
377
+ when RBS::AST::Declarations::TypeAlias
378
+ set << decl.name
379
+ when RBS::AST::Declarations::ClassAlias, RBS::AST::Declarations::ModuleAlias
380
+ set << decl.new_name
381
+ end
382
+ end
383
+
384
+ def add_descendants(graph:, names:, set:)
385
+ set.merge(names)
386
+ names.each do |name|
387
+ case
388
+ when name.interface?
389
+ graph.each_descendant(RBS::AncestorGraph::InstanceNode.new(type_name: name)) do |node|
390
+ set << node.type_name
391
+ end
392
+ when name.class?
393
+ graph.each_descendant(RBS::AncestorGraph::InstanceNode.new(type_name: name)) do |node|
394
+ set << node.type_name
395
+ end
396
+ graph.each_descendant(RBS::AncestorGraph::SingletonNode.new(type_name: name)) do |node|
397
+ set << node.type_name
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ def add_nested_decls(env:, names:, set:)
404
+ tops = names.each_with_object(Set[]) do |name, tops|
405
+ unless name.namespace.empty?
406
+ tops << name.namespace.path[0]
407
+ end
408
+ end
409
+
410
+ env.class_decls.each_key do |name|
411
+ unless name.namespace.empty?
412
+ if tops.include?(name.namespace.path[0])
413
+ set << name
414
+ end
415
+ end
416
+ end
417
+
418
+ env.interface_decls.each_key do |name|
419
+ unless name.namespace.empty?
420
+ if tops.include?(name.namespace.path[0])
421
+ set << name
422
+ end
423
+ end
424
+ end
425
+ end
426
+ end
427
+ end
428
+ end
@@ -0,0 +1,68 @@
1
+ module Steep
2
+ module Services
3
+ class StatsCalculator
4
+ class SuccessStats < Struct.new(:target, :path, :typed_calls_count, :untyped_calls_count, :error_calls_count, keyword_init: true)
5
+ def as_json
6
+ {
7
+ type: "success",
8
+ target: target.name.to_s,
9
+ path: path.to_s,
10
+ typed_calls: typed_calls_count,
11
+ untyped_calls: untyped_calls_count,
12
+ error_calls: error_calls_count,
13
+ total_calls: typed_calls_count + untyped_calls_count + error_calls_count
14
+ }
15
+ end
16
+ end
17
+ class ErrorStats < Struct.new(:target, :path, keyword_init: true)
18
+ def as_json
19
+ {
20
+ type: "error",
21
+ target: target.name.to_s,
22
+ path: path.to_s
23
+ }
24
+ end
25
+ end
26
+
27
+ attr_reader :service
28
+
29
+ def initialize(service:)
30
+ @service = service
31
+ end
32
+
33
+ def project
34
+ service.project
35
+ end
36
+
37
+ def calc_stats(target, file:)
38
+ if typing = file.typing
39
+ typed = 0
40
+ untyped = 0
41
+ errors = 0
42
+ typing.method_calls.each_value do |call|
43
+ case call
44
+ when TypeInference::MethodCall::Typed
45
+ typed += 1
46
+ when TypeInference::MethodCall::Untyped
47
+ untyped += 1
48
+ when TypeInference::MethodCall::Error, TypeInference::MethodCall::NoMethodError
49
+ errors += 1
50
+ else
51
+ raise
52
+ end
53
+ end
54
+
55
+ SuccessStats.new(
56
+ target: target,
57
+ path: file.path,
58
+ typed_calls_count: typed,
59
+ untyped_calls_count: untyped,
60
+ error_calls_count: errors
61
+ )
62
+ else
63
+ ErrorStats.new(target: target, path: file.path)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end