typeprof 0.15.3 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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