typeprof 0.15.3 → 0.20.0

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.
@@ -26,7 +26,7 @@ module TypeProf
26
26
  end
27
27
 
28
28
  def show_message(terminated, output)
29
- if Config.options[:show_typeprof_version]
29
+ if Config.current.options[:show_typeprof_version]
30
30
  output.puts "# TypeProf #{ VERSION }"
31
31
  output.puts
32
32
  end
@@ -38,7 +38,7 @@ module TypeProf
38
38
 
39
39
  def show_error(errors, backward_edge, output)
40
40
  return if errors.empty?
41
- return unless Config.options[:show_errors]
41
+ return unless Config.current.options[:show_errors]
42
42
 
43
43
  output.puts "# Errors"
44
44
  errors.each do |ep, msg|
@@ -110,16 +110,17 @@ module TypeProf
110
110
  @scratch.namespace = class_def.name
111
111
 
112
112
  consts = {}
113
- class_def.consts.each do |name, (ty, absolute_path)|
113
+ class_def.consts.each do |name, (ty, loc)|
114
+ next unless loc
114
115
  next if ty.is_a?(Type::Class)
115
- next if !absolute_path || Config.check_dir_filter(absolute_path) == :exclude
116
+ next if Config.current.check_dir_filter(loc[0]) == :exclude
116
117
  consts[name] = ty.screen_name(@scratch)
117
118
  end
118
119
 
119
120
  modules = class_def.modules.to_h do |kind, mods|
120
121
  mods = mods.to_h do |singleton, mods|
121
122
  mods = mods.filter_map do |mod_def, _type_args, absolute_paths|
122
- next if absolute_paths.all? {|path| !path || Config.check_dir_filter(path) == :exclude }
123
+ next if absolute_paths.all? {|path| !path || Config.current.check_dir_filter(path) == :exclude }
123
124
  Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
124
125
  end
125
126
  [singleton, mods]
@@ -142,7 +143,7 @@ module TypeProf
142
143
 
143
144
  ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
144
145
 
145
- next if Config.check_dir_filter(ctx.iseq.absolute_path) == :exclude
146
+ next if Config.current.check_dir_filter(ctx.iseq.absolute_path) == :exclude
146
147
 
147
148
  method_name = mid
148
149
  method_name = "self.#{ method_name }" if singleton
@@ -152,7 +153,7 @@ module TypeProf
152
153
  source_locations[key] ||= ctx.iseq.source_location(0)
153
154
  (methods[key] ||= []) << @scratch.show_method_signature(ctx)
154
155
  when AliasMethodDef
155
- next if mdef.def_ep && Config.check_dir_filter(mdef.def_ep.source_location) == :exclude
156
+ next if mdef.def_ep && Config.current.check_dir_filter(mdef.def_ep.source_location) == :exclude
156
157
  alias_name, orig_name = mid, mdef.orig_mid
157
158
  if singleton
158
159
  alias_name = "self.#{ alias_name }"
@@ -165,7 +166,7 @@ module TypeProf
165
166
  when AttrMethodDef
166
167
  next if !mdef.def_ep
167
168
  absolute_path = mdef.def_ep.ctx.iseq.absolute_path
168
- next if !absolute_path || Config.check_dir_filter(absolute_path) == :exclude
169
+ next if !absolute_path || Config.current.check_dir_filter(absolute_path) == :exclude
169
170
  mid = mid.to_s[0..-2].to_sym if mid.to_s.end_with?("=")
170
171
  method_name = mid
171
172
  method_name = "self.#{ mid }" if singleton
@@ -188,13 +189,14 @@ module TypeProf
188
189
  key = [:rbs, method_name]
189
190
  methods[key] = sigs
190
191
  visibilities[key] ||= mdef.pub_meth
192
+ source_locations[key] ||= mdef.iseq&.source_location(0)
191
193
  end
192
194
  end
193
195
  end
194
196
  end
195
197
 
196
198
  ivars = ivars.map do |(singleton, var), entry|
197
- next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
199
+ next if entry.absolute_paths.all? {|path| Config.current.check_dir_filter(path) == :exclude }
198
200
  ty = entry.type
199
201
  next unless var.to_s.start_with?("@")
200
202
  var = "self.#{ var }" if singleton
@@ -204,12 +206,12 @@ module TypeProf
204
206
  end.compact
205
207
 
206
208
  cvars = cvars.map do |var, entry|
207
- next if entry.absolute_paths.all? {|path| Config.check_dir_filter(path) == :exclude }
209
+ next if entry.absolute_paths.all? {|path| Config.current.check_dir_filter(path) == :exclude }
208
210
  next if entry.rbs_declared
209
211
  [var, entry.type.screen_name(@scratch)]
210
212
  end.compact
211
213
 
212
- if !class_def.absolute_path || Config.check_dir_filter(class_def.absolute_path) == :exclude
214
+ if !class_def.absolute_path || Config.current.check_dir_filter(class_def.absolute_path) == :exclude
213
215
  if methods.keys.all? {|type,| type == :rbs }
214
216
  return nil if consts.empty? && modules[:before][true].empty? && modules[:before][false].empty? && modules[:after][true].empty? && modules[:after][false].empty? && ivars.empty? && cvars.empty? && inner_classes.empty?
215
217
  end
@@ -232,8 +234,182 @@ module TypeProf
232
234
  )
233
235
  end
234
236
 
237
+ def conv_class_lsp(namespace, class_def)
238
+ @scratch.namespace = namespace
239
+
240
+ if class_def.klass_obj.superclass != :__root__ && class_def.klass_obj.superclass
241
+ omit = class_def.klass_obj.superclass == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
242
+ superclass = omit ? nil : @scratch.get_class_name(class_def.klass_obj.superclass)
243
+ type_args = class_def.klass_obj.superclass_type_args
244
+ if type_args && !type_args.empty?
245
+ superclass += "[#{ type_args.map {|ty| ty.screen_name(@scratch) }.join(", ") }]"
246
+ end
247
+ end
248
+
249
+ @scratch.namespace = class_def.name
250
+
251
+ consts = {}
252
+ class_def.consts.each do |name, (ty, loc)|
253
+ next unless loc
254
+ next if ty.is_a?(Type::Class)
255
+ next if Config.current.check_dir_filter(loc[0]) == :exclude
256
+ consts[name] = ty.screen_name(@scratch)
257
+ end
258
+
259
+ modules = class_def.modules.to_h do |kind, mods|
260
+ mods = mods.to_h do |singleton, mods|
261
+ mods = mods.filter_map do |mod_def, _type_args, absolute_paths|
262
+ next if absolute_paths.all? {|path| !path || Config.current.check_dir_filter(path) == :exclude }
263
+ Type::Instance.new(mod_def.klass_obj).screen_name(@scratch)
264
+ end
265
+ [singleton, mods]
266
+ end
267
+ [kind, mods]
268
+ end
269
+
270
+ visibilities = {}
271
+ source_locations = {}
272
+ methods = {}
273
+ ivars = class_def.ivars.dump
274
+ cvars = class_def.cvars.dump
275
+
276
+ class_def.methods.each do |(singleton, mid), mdefs|
277
+ mdefs.each do |mdef|
278
+ case mdef
279
+ when ISeqMethodDef
280
+ ctxs = @iseq_method_to_ctxs[mdef]
281
+ next unless ctxs
282
+
283
+ ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
284
+
285
+ next if Config.current.check_dir_filter(ctx.iseq.absolute_path) == :exclude
286
+
287
+ method_name = mid
288
+ method_name = "self.#{ method_name }" if singleton
289
+
290
+ key = [:iseq, method_name]
291
+ visibilities[key] ||= mdef.pub_meth
292
+ source_locations[key] ||= [ctx.iseq.source_location(0)]
293
+ sig = @scratch.show_method_signature(ctx)
294
+ (methods[key] ||= []) << sig if sig
295
+ when AliasMethodDef
296
+ alias_name, orig_name = mid, mdef.orig_mid
297
+ if singleton
298
+ alias_name = "self.#{ alias_name }"
299
+ orig_name = "self.#{ orig_name }"
300
+ end
301
+ key = [:alias, alias_name]
302
+ visibilities[key] ||= mdef.pub_meth
303
+ source_locations[key] ||= [mdef.def_ep&.source_location]
304
+ methods[key] = orig_name
305
+ when AttrMethodDef
306
+ next if !mdef.def_ep
307
+ absolute_path = mdef.def_ep.ctx.iseq.absolute_path
308
+ next if !absolute_path || Config.current.check_dir_filter(absolute_path) == :exclude
309
+ mid = mid.to_s[0..-2].to_sym if mid.to_s.end_with?("=")
310
+ method_name = mid
311
+ method_name = "self.#{ mid }" if singleton
312
+ method_name = [method_name, :"@#{ mid }" != mdef.ivar]
313
+ key = [:attr, method_name]
314
+ visibilities[key] ||= mdef.pub_meth
315
+ source_locations[key] ||= [mdef.def_ep.source_location]
316
+ if methods[key]
317
+ if methods[key][0] != mdef.kind
318
+ methods[key][0] = :accessor
319
+ end
320
+ else
321
+ entry = ivars[[singleton, mdef.ivar]]
322
+ ty = entry ? entry.type : Type.any
323
+ methods[key] = [mdef.kind, ty.screen_name(@scratch), ty.include_untyped?(@scratch)]
324
+ end
325
+ when TypedMethodDef
326
+ if mdef.rbs_source
327
+ method_name, sigs, rbs_code_range = mdef.rbs_source
328
+ key = [:rbs, method_name]
329
+ methods[key] = sigs
330
+ visibilities[key] ||= mdef.pub_meth
331
+ source_locations[key] ||= [mdef.iseq&.source_location(0), rbs_code_range]
332
+ end
333
+ end
334
+ end
335
+ end
336
+
337
+ ivars = ivars.map do |(singleton, var), entry|
338
+ next if entry.absolute_paths.all? {|path| Config.current.check_dir_filter(path) == :exclude }
339
+ ty = entry.type
340
+ next unless var.to_s.start_with?("@")
341
+ var = "self.#{ var }" if singleton
342
+ next if methods[[:attr, [singleton ? "self.#{ var.to_s[1..] }" : var.to_s[1..].to_sym, false]]]
343
+ next if entry.rbs_declared
344
+ [var, ty.screen_name(@scratch)]
345
+ end.compact
346
+
347
+ cvars = cvars.map do |var, entry|
348
+ next if entry.absolute_paths.all? {|path| Config.current.check_dir_filter(path) == :exclude }
349
+ next if entry.rbs_declared
350
+ [var, entry.type.screen_name(@scratch)]
351
+ end.compact
352
+
353
+ if !class_def.absolute_path || Config.current.check_dir_filter(class_def.absolute_path) == :exclude
354
+ if methods.keys.all? {|type,| type == :rbs }
355
+ return nil if consts.empty? && modules[:before][true].empty? && modules[:before][false].empty? && modules[:after][true].empty? && modules[:after][false].empty? && ivars.empty? && cvars.empty?
356
+ end
357
+ end
358
+
359
+ @scratch.namespace = nil
360
+
361
+ ClassData.new(
362
+ kind: class_def.kind,
363
+ name: class_def.name,
364
+ superclass: superclass,
365
+ consts: consts,
366
+ modules: modules,
367
+ ivars: ivars,
368
+ cvars: cvars,
369
+ methods: methods,
370
+ visibilities: visibilities,
371
+ source_locations: source_locations,
372
+ )
373
+ end
374
+
235
375
  ClassData = Struct.new(:kind, :name, :superclass, :consts, :modules, :ivars, :cvars, :methods, :visibilities, :source_locations, :inner_classes, keyword_init: true)
236
376
 
377
+ def show_lsp
378
+ res = []
379
+ @class_defs.each_value do |class_def|
380
+ class_data = conv_class_lsp([], class_def)
381
+ next unless class_data
382
+ class_data.methods.each do |key, arg|
383
+ source_location, rbs_code_range = class_data.source_locations[key]
384
+ type, (method_name, hidden) = key
385
+ case type
386
+ when :attr
387
+ kind, ty, untyped = *arg
388
+ line = "attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" }: #{ ty }"
389
+ when :rbs
390
+ sigs = arg.sort.join(" | ")
391
+ line = "# def #{ method_name }: #{ sigs }"
392
+ when :iseq
393
+ sigs = []
394
+ untyped = false
395
+ arg.each do |sig, untyped0|
396
+ sigs << sig
397
+ untyped ||= untyped0
398
+ end
399
+ sigs = sigs.sort.join(" | ")
400
+ line = "def #{ method_name }: #{ sigs }"
401
+ when :alias
402
+ orig_name = arg
403
+ line = "alias #{ method_name } #{ orig_name }"
404
+ end
405
+ if source_location =~ /:(\d+)$/
406
+ res << [$`, $1.to_i, line, rbs_code_range, class_data.kind, class_data.name]
407
+ end
408
+ end
409
+ end
410
+ res
411
+ end
412
+
237
413
  def show(stat_eps, output)
238
414
  # make the class hierarchy
239
415
  root = {}
@@ -270,7 +446,7 @@ module TypeProf
270
446
  coverage = {}
271
447
  stat_eps.each do |ep|
272
448
  path = ep.ctx.iseq.path
273
- lineno = ep.ctx.iseq.linenos[ep.pc] - 1
449
+ lineno = ep.ctx.iseq.insns[ep.pc].lineno - 1
274
450
  (coverage[path] ||= [])[lineno] ||= 0
275
451
  (coverage[path] ||= [])[lineno] += 1
276
452
  end
@@ -340,7 +516,7 @@ module TypeProf
340
516
  prev_vis = vis
341
517
  end
342
518
  source_location = class_data.source_locations[key]
343
- if Config.options[:show_source_locations] && source_location
519
+ if Config.current.options[:show_source_locations] && source_location
344
520
  lines << nil
345
521
  lines << (indent + " # #{ source_location }")
346
522
  end
@@ -348,7 +524,7 @@ module TypeProf
348
524
  case type
349
525
  when :attr
350
526
  kind, ty, untyped = *arg
351
- exclude = Config.options[:exclude_untyped] && untyped ? "#" : " " # XXX
527
+ exclude = Config.current.options[:exclude_untyped] && untyped ? "#" : " " # XXX
352
528
  lines << (indent + "#{ exclude } attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" }: #{ ty }")
353
529
  when :rbs
354
530
  sigs = arg.sort.join("\n" + indent + "#" + " " * (method_name.size + 5) + "| ")
@@ -361,7 +537,7 @@ module TypeProf
361
537
  untyped ||= untyped0
362
538
  end
363
539
  sigs = sigs.sort.join("\n" + indent + " " * (method_name.size + 6) + "| ")
364
- exclude = Config.options[:exclude_untyped] && untyped ? "#" : " " # XXX
540
+ exclude = Config.current.options[:exclude_untyped] && untyped ? "#" : " " # XXX
365
541
  lines << (indent + "#{ exclude } def #{ method_name }: #{ sigs }")
366
542
  when :alias
367
543
  orig_name = arg
@@ -4,9 +4,14 @@ module TypeProf
4
4
  class RBSReader
5
5
  def initialize
6
6
  @repo = RBS::Repository.new
7
- Config.gem_repo_dirs.each do |dir|
7
+ Config.current.gem_repo_dirs.each do |dir|
8
8
  @repo.add(Pathname(dir))
9
9
  end
10
+ collection_path = Config.current.collection_path
11
+ if collection_path&.exist?
12
+ collection_lock = RBS::Collection::Config.lockfile_of(collection_path)
13
+ @repo.add(collection_lock.repo_path)
14
+ end
10
15
  @env, @builtin_env_json = RBSReader.get_builtin_env
11
16
  end
12
17
 
@@ -66,6 +71,14 @@ module TypeProf
66
71
  RBSReader.load_rbs(@env, new_decls)
67
72
  end
68
73
 
74
+ def load_rbs_collection(collection_path)
75
+ loader = RBS::EnvironmentLoader.new(core_root: nil)
76
+ collection_lock = RBS::Collection::Config.lockfile_of(collection_path)
77
+ loader.add_collection(collection_lock)
78
+ new_decls = loader.load(env: @env).map {|decl,| decl }
79
+ RBSReader.load_rbs(@env, new_decls)
80
+ end
81
+
69
82
  def self.load_rbs(env, new_decls)
70
83
  all_env = env.resolve_type_names
71
84
  resolver = RBS::TypeNameResolver.from_env(all_env)
@@ -157,7 +170,11 @@ module TypeProf
157
170
  end
158
171
 
159
172
  method_def = conv_method_def(method_types, visibility)
160
- rbs_source = [(member.kind == :singleton ? "self." : "") + member.name.to_s, member.types.map {|type| type.location.source }]
173
+ rbs_source = [
174
+ (member.kind == :singleton ? "self." : "") + member.name.to_s,
175
+ member.types.map {|type| type.location.source },
176
+ [member.location.name, CodeRange.from_rbs(member.location)],
177
+ ]
161
178
  if member.instance?
162
179
  methods[[false, name]] = method_def
163
180
  rbs_sources[[false, name]] = rbs_source
@@ -514,6 +531,10 @@ module TypeProf
514
531
  Import.new(scratch, scratch.rbs_reader.load_rbs_string(rbs_name, rbs_code)).import(true)
515
532
  end
516
533
 
534
+ def self.import_rbs_collection(scratch, collection_path)
535
+ Import.new(scratch, scratch.rbs_reader.load_rbs_collection(collection_path)).import(true)
536
+ end
537
+
517
538
  def initialize(scratch, json)
518
539
  @scratch = scratch
519
540
  @json = json
@@ -529,7 +550,7 @@ module TypeProf
529
550
  superclass = path_to_klass(superclass) if superclass
530
551
  base_klass = path_to_klass(classpath[0..-2])
531
552
 
532
- klass = @scratch.get_constant(base_klass, name)
553
+ klass, = @scratch.get_constant(base_klass, name)
533
554
  if klass.is_a?(Type::Any)
534
555
  klass = @scratch.new_class(base_klass, name, type_params, superclass, nil)
535
556
 
@@ -748,7 +769,7 @@ module TypeProf
748
769
  def path_to_klass(path)
749
770
  klass = Type::Builtin[:obj]
750
771
  path.each do |name|
751
- klass = @scratch.get_constant(klass, name)
772
+ klass, = @scratch.get_constant(klass, name)
752
773
  if klass == Type.any
753
774
  raise TypeProfError.new("A constant `#{ path.join("::") }' is used but not defined in RBS")
754
775
  end