typeprof 0.2.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -2
- data/.gitignore +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +10 -21
- data/LICENSE +21 -0
- data/README.md +6 -0
- data/doc/demo.md +398 -0
- data/doc/doc.ja.md +6 -1
- data/doc/doc.md +7 -2
- data/exe/typeprof +2 -1
- data/lib/typeprof.rb +9 -0
- data/lib/typeprof/analyzer.rb +427 -325
- data/lib/typeprof/arguments.rb +405 -0
- data/lib/typeprof/block.rb +136 -0
- data/lib/typeprof/builtin.rb +36 -25
- data/lib/typeprof/cli.rb +51 -98
- data/lib/typeprof/config.rb +114 -0
- data/lib/typeprof/container-type.rb +280 -92
- data/lib/typeprof/export.rb +197 -108
- data/lib/typeprof/import.rb +134 -80
- data/lib/typeprof/iseq.rb +42 -1
- data/lib/typeprof/method.rb +178 -82
- data/lib/typeprof/type.rb +228 -369
- data/lib/typeprof/utils.rb +4 -18
- data/lib/typeprof/version.rb +3 -0
- data/smoke/arguments2.rb +55 -0
- data/smoke/array-each3.rb +1 -4
- data/smoke/array12.rb +1 -1
- data/smoke/array6.rb +1 -0
- data/smoke/block-ambiguous.rb +36 -0
- data/smoke/block-args1-rest.rb +62 -0
- data/smoke/block-args1.rb +59 -0
- data/smoke/block-args2-rest.rb +62 -0
- data/smoke/block-args2.rb +59 -0
- data/smoke/block-args3-rest.rb +73 -0
- data/smoke/block-args3.rb +70 -0
- data/smoke/block-blockarg.rb +27 -0
- data/smoke/block-kwarg.rb +52 -0
- data/smoke/block10.rb +1 -1
- data/smoke/block11.rb +1 -1
- data/smoke/block14.rb +17 -0
- data/smoke/block4.rb +2 -2
- data/smoke/block5.rb +1 -0
- data/smoke/block6.rb +1 -1
- data/smoke/block7.rb +0 -2
- data/smoke/block8.rb +2 -2
- data/smoke/block9.rb +1 -1
- data/smoke/blown.rb +1 -1
- data/smoke/class-hierarchy.rb +54 -0
- data/smoke/class-hierarchy2.rb +27 -0
- data/smoke/constant1.rb +11 -6
- data/smoke/constant2.rb +2 -0
- data/smoke/cvar.rb +1 -0
- data/smoke/demo10.rb +1 -1
- data/smoke/demo8.rb +2 -2
- data/smoke/demo9.rb +1 -3
- data/smoke/flow7.rb +1 -7
- data/smoke/flow8.rb +13 -0
- data/smoke/hash-fetch.rb +3 -3
- data/smoke/hash-merge-bang.rb +11 -0
- data/smoke/hash1.rb +1 -1
- data/smoke/hash3.rb +1 -1
- data/smoke/hash4.rb +1 -1
- data/smoke/instance_eval.rb +1 -1
- data/smoke/int_times.rb +1 -1
- data/smoke/ivar2.rb +1 -1
- data/smoke/keyword3.rb +1 -2
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwsplat1.rb +1 -1
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/module4.rb +2 -0
- data/smoke/multiple-superclass.rb +4 -0
- data/smoke/next2.rb +1 -1
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.rb +1 -1
- data/smoke/optional3.rb +10 -0
- data/smoke/pattern-match1.rb +23 -0
- data/smoke/pattern-match2.rb +15 -0
- data/smoke/proc4.rb +1 -1
- data/smoke/rbs-extend.rb +9 -0
- data/smoke/rbs-extend.rbs +7 -0
- data/smoke/rbs-interface.rb +24 -0
- data/smoke/rbs-interface.rbs +12 -0
- data/smoke/rbs-proc1.rb +9 -0
- data/smoke/rbs-proc1.rbs +3 -0
- data/smoke/rbs-proc2.rb +20 -0
- data/smoke/rbs-proc2.rbs +3 -0
- data/smoke/rbs-proc3.rb +13 -0
- data/smoke/rbs-proc3.rbs +4 -0
- data/smoke/rbs-record.rb +17 -0
- data/smoke/rbs-record.rbs +4 -0
- data/smoke/rbs-tyvar.rb +18 -0
- data/smoke/rbs-tyvar.rbs +5 -0
- data/smoke/rbs-tyvar2.rb +20 -0
- data/smoke/rbs-tyvar2.rbs +9 -0
- data/smoke/rbs-tyvar3.rb +17 -0
- data/smoke/rbs-tyvar3.rbs +5 -0
- data/smoke/rbs-tyvar4.rb +36 -0
- data/smoke/rbs-tyvar5.rb +12 -0
- data/smoke/rbs-tyvar5.rbs +8 -0
- data/smoke/rest1.rb +1 -1
- data/smoke/rest2.rb +1 -1
- data/smoke/rest3.rb +1 -1
- data/smoke/rest5.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +1 -1
- data/smoke/return.rb +1 -1
- data/smoke/singleton_method.rb +3 -0
- data/smoke/step.rb +1 -1
- data/smoke/struct.rb +4 -3
- data/smoke/struct3.rb +14 -0
- data/smoke/symbol-proc.rb +24 -0
- data/smoke/uninitialize-var.rb +12 -0
- data/smoke/user-demo.rb +15 -0
- data/smoke/wrong-extend.rb +1 -0
- data/typeprof.gemspec +4 -2
- metadata +53 -6
- data/run.sh +0 -3
- data/smoke/variadic1.rb.notyet +0 -5
data/lib/typeprof/builtin.rb
CHANGED
|
@@ -54,21 +54,29 @@ module TypeProf
|
|
|
54
54
|
ctn[ret_ty, ep, env]
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
def vmcore_raise(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
58
|
+
# no-op
|
|
59
|
+
end
|
|
60
|
+
|
|
57
61
|
def lambda(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
58
62
|
ctn[aargs.blk_ty, ep, env]
|
|
59
63
|
end
|
|
60
64
|
|
|
61
65
|
def proc_call(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
62
|
-
|
|
63
|
-
scratch.do_invoke_block(given_block, recv, aargs, ep, env, &ctn)
|
|
66
|
+
scratch.do_invoke_block(recv, aargs, ep, env, &ctn)
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
def object_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
67
|
-
|
|
70
|
+
if recv.type_params.size >= 1
|
|
71
|
+
ty = Type::ContainerType.create_empty_instance(recv)
|
|
72
|
+
env, ty = scratch.localize_type(ty, env, ep, AllocationSite.new(ep).add_id(:object_s_new))
|
|
73
|
+
else
|
|
74
|
+
ty = Type::Instance.new(recv)
|
|
75
|
+
end
|
|
68
76
|
meths = scratch.get_method(recv, false, :initialize)
|
|
69
77
|
meths.flat_map do |meth|
|
|
70
78
|
meth.do_send(ty, :initialize, aargs, ep, env, scratch) do |ret_ty, ep, env|
|
|
71
|
-
ctn[
|
|
79
|
+
ctn[ty, ep, env]
|
|
72
80
|
end
|
|
73
81
|
end
|
|
74
82
|
end
|
|
@@ -118,7 +126,7 @@ module TypeProf
|
|
|
118
126
|
else
|
|
119
127
|
mid_ty = aargs.rest_ty
|
|
120
128
|
end
|
|
121
|
-
aargs = ActualArguments.new(aargs.lead_tys[1..-1], aargs.rest_ty, aargs.
|
|
129
|
+
aargs = ActualArguments.new(aargs.lead_tys[1..-1], aargs.rest_ty, aargs.kw_tys, aargs.blk_ty)
|
|
122
130
|
found = false
|
|
123
131
|
mid_ty.each_child do |mid|
|
|
124
132
|
if mid.is_a?(Type::Symbol)
|
|
@@ -138,9 +146,8 @@ module TypeProf
|
|
|
138
146
|
ctn[type.any, ep, env]
|
|
139
147
|
return
|
|
140
148
|
end
|
|
141
|
-
naargs = ActualArguments.new([recv],
|
|
142
|
-
|
|
143
|
-
scratch.do_invoke_block(given_block, aargs.blk_ty, naargs, ep, env, replace_recv_ty: recv) do |_ret_ty, ep|
|
|
149
|
+
naargs = ActualArguments.new([recv], nil, {}, Type.nil)
|
|
150
|
+
scratch.do_invoke_block(aargs.blk_ty, naargs, ep, env, replace_recv_ty: recv) do |_ret_ty, ep|
|
|
144
151
|
ctn[recv, ep, scratch.return_envs[ep]]
|
|
145
152
|
end
|
|
146
153
|
end
|
|
@@ -244,7 +251,10 @@ module TypeProf
|
|
|
244
251
|
def array_aset(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
245
252
|
return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
|
|
246
253
|
|
|
247
|
-
|
|
254
|
+
if aargs.lead_tys.size != 2
|
|
255
|
+
#raise NotImplementedError # XXX
|
|
256
|
+
ctn[Type.any, ep, env]
|
|
257
|
+
end
|
|
248
258
|
|
|
249
259
|
idx = aargs.lead_tys.first
|
|
250
260
|
if idx.is_a?(Type::Literal)
|
|
@@ -256,7 +266,7 @@ module TypeProf
|
|
|
256
266
|
|
|
257
267
|
ty = aargs.lead_tys.last
|
|
258
268
|
|
|
259
|
-
env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
|
|
269
|
+
env = scratch.update_container_elem_types(env, ep, recv.id, recv.base_type) do |elems|
|
|
260
270
|
elems.update(idx, ty)
|
|
261
271
|
end
|
|
262
272
|
|
|
@@ -307,7 +317,7 @@ module TypeProf
|
|
|
307
317
|
return ctn[ty, ep, env]
|
|
308
318
|
end
|
|
309
319
|
|
|
310
|
-
env = scratch.update_container_elem_types(env, ep, recv.id) do |elems|
|
|
320
|
+
env = scratch.update_container_elem_types(env, ep, recv.id, recv.base_type) do |elems|
|
|
311
321
|
elems.update(idx, ty)
|
|
312
322
|
end
|
|
313
323
|
|
|
@@ -316,14 +326,12 @@ module TypeProf
|
|
|
316
326
|
|
|
317
327
|
def struct_initialize(recv, mid, aargs, ep, env, scratch, &ctn)
|
|
318
328
|
recv = Type::Instance.new(recv)
|
|
319
|
-
scratch.
|
|
320
|
-
|
|
321
|
-
ty.elems.lead_tys.zip(aargs.lead_tys) do |sym, ty|
|
|
329
|
+
scratch.add_ivar_read!(recv, :_members, ep) do |member_ary_ty, ep|
|
|
330
|
+
member_ary_ty.elems.lead_tys.zip(aargs.lead_tys) do |sym, ty|
|
|
322
331
|
ty ||= Type.nil
|
|
323
332
|
scratch.set_instance_variable(recv, sym.sym, ty, ep, env)
|
|
324
333
|
end
|
|
325
334
|
end
|
|
326
|
-
#scratch.set_instance_variable(recv, , ty, ep, env)
|
|
327
335
|
ctn[recv, ep, env]
|
|
328
336
|
end
|
|
329
337
|
|
|
@@ -337,9 +345,8 @@ module TypeProf
|
|
|
337
345
|
return
|
|
338
346
|
end
|
|
339
347
|
if struct_klass != recv
|
|
340
|
-
scratch.
|
|
341
|
-
|
|
342
|
-
scratch.set_instance_variable(Type::Instance.new(recv), :_members, ty, ep, env)
|
|
348
|
+
scratch.add_ivar_read!(Type::Instance.new(struct_klass), :_members, ep) do |ty, ep|
|
|
349
|
+
scratch.add_ivar_write!(Type::Instance.new(recv), :_members, ty, ep)
|
|
343
350
|
end
|
|
344
351
|
end
|
|
345
352
|
meths = scratch.get_method(recv, false, :initialize)
|
|
@@ -364,7 +371,7 @@ module TypeProf
|
|
|
364
371
|
fields = fields.map {|field| Type::Symbol.new(field, Type::Instance.new(Type::Builtin[:sym])) }
|
|
365
372
|
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
|
366
373
|
fields = Type::Array.new(Type::Array::Elements.new(fields), base_ty)
|
|
367
|
-
scratch.
|
|
374
|
+
scratch.add_ivar_write!(Type::Instance.new(struct_klass), :_members, fields, ep)
|
|
368
375
|
#set_singleton_custom_method(struct_klass, :members, Builtin.method(:...))
|
|
369
376
|
|
|
370
377
|
ctn[struct_klass, ep, env]
|
|
@@ -372,10 +379,10 @@ module TypeProf
|
|
|
372
379
|
|
|
373
380
|
def self.file_load(path, ep, env, scratch, &ctn)
|
|
374
381
|
iseq = ISeq.compile(path)
|
|
375
|
-
callee_ep, callee_env =
|
|
382
|
+
callee_ep, callee_env = TypeProf.starting_state(iseq)
|
|
376
383
|
scratch.merge_env(callee_ep, callee_env)
|
|
377
384
|
|
|
378
|
-
scratch.add_callsite!(callee_ep.ctx,
|
|
385
|
+
scratch.add_callsite!(callee_ep.ctx, ep, env) do |_ret_ty, ep|
|
|
379
386
|
ret_ty = Type::Instance.new(Type::Builtin[:true])
|
|
380
387
|
ctn[ret_ty, ep, env]
|
|
381
388
|
end
|
|
@@ -482,8 +489,8 @@ module TypeProf
|
|
|
482
489
|
def self.setup_initial_global_env(scratch)
|
|
483
490
|
klass_basic_obj = scratch.new_class(nil, :BasicObject, [], :__root__, nil) # cbase, name, superclass
|
|
484
491
|
klass_obj = scratch.new_class(nil, :Object, [], klass_basic_obj, nil)
|
|
485
|
-
scratch.add_constant(klass_obj,
|
|
486
|
-
scratch.add_constant(klass_obj,
|
|
492
|
+
scratch.add_constant(klass_obj, :Object, klass_obj, nil)
|
|
493
|
+
scratch.add_constant(klass_obj, :BasicObject, klass_basic_obj, nil)
|
|
487
494
|
|
|
488
495
|
Type::Builtin[:basic_obj] = klass_basic_obj
|
|
489
496
|
Type::Builtin[:obj] = klass_obj
|
|
@@ -518,6 +525,7 @@ module TypeProf
|
|
|
518
525
|
scratch.set_custom_method(klass_vmcore, :"core#set_method_alias", Builtin.method(:vmcore_set_method_alias))
|
|
519
526
|
scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
|
|
520
527
|
scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
|
|
528
|
+
scratch.set_custom_method(klass_vmcore, :"core#raise", Builtin.method(:vmcore_raise))
|
|
521
529
|
scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
|
|
522
530
|
scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
|
|
523
531
|
scratch.set_singleton_custom_method(klass_obj, :"attr_accessor", Builtin.method(:module_attr_accessor))
|
|
@@ -529,6 +537,7 @@ module TypeProf
|
|
|
529
537
|
scratch.set_custom_method(klass_obj, :class, Builtin.method(:object_class))
|
|
530
538
|
scratch.set_custom_method(klass_obj, :send, Builtin.method(:object_send))
|
|
531
539
|
scratch.set_custom_method(klass_obj, :instance_eval, Builtin.method(:object_instance_eval))
|
|
540
|
+
scratch.set_custom_method(klass_obj, :proc, Builtin.method(:lambda))
|
|
532
541
|
|
|
533
542
|
scratch.set_custom_method(klass_module, :include, Builtin.method(:module_include))
|
|
534
543
|
scratch.set_custom_method(klass_module, :extend, Builtin.method(:module_extend))
|
|
@@ -551,8 +560,10 @@ module TypeProf
|
|
|
551
560
|
scratch.set_custom_method(klass_obj, :require_relative, Builtin.method(:kernel_require_relative))
|
|
552
561
|
scratch.set_custom_method(klass_obj, :Array, Builtin.method(:kernel_Array))
|
|
553
562
|
|
|
554
|
-
|
|
555
|
-
|
|
563
|
+
# ENV: Hash[String, String]
|
|
564
|
+
str_ty = Type::Instance.new(Type::Builtin[:str])
|
|
565
|
+
env_ty = Type.gen_hash {|h| h[str_ty] = Type.optional(str_ty) }
|
|
566
|
+
scratch.add_constant(klass_obj, :ENV, env_ty, false)
|
|
556
567
|
end
|
|
557
568
|
end
|
|
558
569
|
end
|
data/lib/typeprof/cli.rb
CHANGED
|
@@ -1,64 +1,62 @@
|
|
|
1
1
|
require "optparse"
|
|
2
|
-
require "rbconfig"
|
|
3
2
|
|
|
4
3
|
module TypeProf
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[:include],
|
|
8
|
-
[:exclude, RbConfig::CONFIG["prefix"]],
|
|
9
|
-
[:exclude, Gem.dir],
|
|
10
|
-
[:exclude, Gem.user_dir],
|
|
11
|
-
]
|
|
4
|
+
module CLI
|
|
5
|
+
module_function
|
|
12
6
|
|
|
13
|
-
def
|
|
7
|
+
def parse(argv)
|
|
14
8
|
opt = OptionParser.new
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
output = nil
|
|
17
11
|
|
|
18
12
|
# Verbose level:
|
|
19
13
|
# * 0: no output
|
|
20
14
|
# * 1: show indicator
|
|
21
15
|
# * 2: debug print
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
opt.on("-
|
|
33
|
-
opt.on("
|
|
34
|
-
opt.on("-
|
|
16
|
+
verbose = 1
|
|
17
|
+
|
|
18
|
+
options = {}
|
|
19
|
+
dir_filter = nil
|
|
20
|
+
gem_rbs_features = []
|
|
21
|
+
version = false
|
|
22
|
+
max_sec = max_iter = nil
|
|
23
|
+
|
|
24
|
+
opt.on("-o OUTFILE") {|v| output = v }
|
|
25
|
+
opt.on("-q", "--quiet") { verbose = 0 }
|
|
26
|
+
opt.on("-v", "--verbose") { options[:show_errors] = true }
|
|
27
|
+
opt.on("--version") { version = true }
|
|
28
|
+
opt.on("-d", "--debug") { verbose = 2 }
|
|
35
29
|
opt.on("-I DIR") {|v| $LOAD_PATH << v }
|
|
36
|
-
opt.on("-r FEATURE") {|v|
|
|
30
|
+
opt.on("-r FEATURE") {|v| gem_rbs_features << v }
|
|
31
|
+
opt.on("--max-second SECOND", Float) {|v| max_sec = v }
|
|
32
|
+
opt.on("--max-iteration TIMES", Integer) {|v| max_iter = v }
|
|
37
33
|
|
|
38
34
|
opt.on("--include-dir DIR") do |dir|
|
|
39
35
|
# When `--include-dir` option is specified as the first directory option,
|
|
40
36
|
# typeprof will exclude any files by default unless a file path matches the explicit option
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
dir_filter ||= [[:exclude]]
|
|
38
|
+
dir_filter << [:include, File.expand_path(dir)]
|
|
43
39
|
end
|
|
44
40
|
opt.on("--exclude-dir DIR") do |dir|
|
|
45
41
|
# When `--exclude-dir` option is specified as the first directory option,
|
|
46
42
|
# typeprof will include any files by default, except Ruby's install directory and Gem directories
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
|
44
|
+
dir_filter << [:exclude, File.expand_path(dir)]
|
|
49
45
|
end
|
|
50
46
|
|
|
51
47
|
opt.on("-f OPTION") do |v|
|
|
52
48
|
key, args = v.split("=", 2)
|
|
53
49
|
case key
|
|
54
50
|
when "type-depth-limit"
|
|
55
|
-
|
|
51
|
+
options[:type_depth_limit] = Integer(args)
|
|
56
52
|
when "pedantic-output"
|
|
57
|
-
|
|
53
|
+
options[:pedantic_output] = true
|
|
58
54
|
when "show-errors"
|
|
59
|
-
|
|
55
|
+
options[:show_errors] = true
|
|
60
56
|
when "show-container-raw-elements"
|
|
61
|
-
|
|
57
|
+
options[:show_container_raw_elements] = true
|
|
58
|
+
when "stackprof"
|
|
59
|
+
options[:stackprof] = args ? args.to_sym : :cpu
|
|
62
60
|
else
|
|
63
61
|
raise OptionParser::InvalidOption.new("unknown option: #{ key }")
|
|
64
62
|
end
|
|
@@ -66,83 +64,38 @@ module TypeProf
|
|
|
66
64
|
|
|
67
65
|
opt.parse!(argv)
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
|
68
|
+
rb_files = []
|
|
69
|
+
rbs_files = []
|
|
72
70
|
argv.each do |path|
|
|
73
71
|
if File.extname(path) == ".rbs"
|
|
74
|
-
|
|
72
|
+
rbs_files << path
|
|
75
73
|
else
|
|
76
|
-
|
|
74
|
+
rb_files << path
|
|
77
75
|
end
|
|
78
76
|
end
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
puts "typeprof #{ VERSION }" if version
|
|
79
|
+
if rb_files.empty?
|
|
80
|
+
exit if version
|
|
81
|
+
raise OptionParser::InvalidOption.new("no input files")
|
|
82
|
+
end
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
ConfigData.new(
|
|
85
|
+
rb_files: rb_files,
|
|
86
|
+
rbs_files: rbs_files,
|
|
87
|
+
output: output,
|
|
88
|
+
gem_rbs_features: gem_rbs_features,
|
|
89
|
+
verbose: verbose,
|
|
90
|
+
dir_filter: dir_filter,
|
|
91
|
+
max_sec: max_sec,
|
|
92
|
+
max_iter: max_iter,
|
|
93
|
+
options: options,
|
|
94
|
+
)
|
|
83
95
|
|
|
84
96
|
rescue OptionParser::InvalidOption
|
|
85
97
|
puts $!
|
|
86
98
|
exit
|
|
87
99
|
end
|
|
88
|
-
|
|
89
|
-
attr_reader :verbose, :options, :dir_filter
|
|
90
|
-
attr_accessor :output
|
|
91
|
-
|
|
92
|
-
def check_dir_filter(path)
|
|
93
|
-
@dir_filter.reverse_each do |cond, dir|
|
|
94
|
-
return cond unless dir
|
|
95
|
-
return cond if path.start_with?(dir)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def run
|
|
100
|
-
scratch = Scratch.new
|
|
101
|
-
Builtin.setup_initial_global_env(scratch)
|
|
102
|
-
|
|
103
|
-
@rbs_features_to_load.each do |feature|
|
|
104
|
-
Import.import_library(scratch, feature)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
prologue_ctx = Context.new(nil, nil, nil)
|
|
108
|
-
prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
|
|
109
|
-
prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
|
|
110
|
-
|
|
111
|
-
@rb_files.each do |path|
|
|
112
|
-
if path == "-"
|
|
113
|
-
iseq = ISeq.compile_str($<.read)
|
|
114
|
-
else
|
|
115
|
-
iseq = ISeq.compile(path)
|
|
116
|
-
end
|
|
117
|
-
ep, env = CLI.starting_state(iseq)
|
|
118
|
-
scratch.merge_env(ep, env)
|
|
119
|
-
scratch.add_callsite!(ep.ctx, nil, prologue_ep, prologue_env) {|ty, ep| }
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
@rbs_files.each do |path|
|
|
123
|
-
Import.import_rbs_file(scratch, path)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
result = scratch.type_profile
|
|
127
|
-
|
|
128
|
-
if @output
|
|
129
|
-
open(@output, "w") do |output|
|
|
130
|
-
scratch.report(result, output)
|
|
131
|
-
end
|
|
132
|
-
else
|
|
133
|
-
scratch.report(result, $stdout)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def self.starting_state(iseq)
|
|
138
|
-
cref = CRef.new(:bottom, Type::Builtin[:obj], false) # object
|
|
139
|
-
recv = Type::Instance.new(Type::Builtin[:obj])
|
|
140
|
-
ctx = Context.new(iseq, cref, nil)
|
|
141
|
-
ep = ExecutionPoint.new(ctx, 0, nil)
|
|
142
|
-
locals = [Type.nil] * iseq.locals.size
|
|
143
|
-
env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
|
|
144
|
-
|
|
145
|
-
return ep, env
|
|
146
|
-
end
|
|
147
100
|
end
|
|
148
101
|
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require "rbconfig"
|
|
2
|
+
|
|
3
|
+
module TypeProf
|
|
4
|
+
ConfigData = Struct.new(
|
|
5
|
+
:rb_files,
|
|
6
|
+
:rbs_files,
|
|
7
|
+
:output,
|
|
8
|
+
:gem_rbs_features,
|
|
9
|
+
:verbose,
|
|
10
|
+
:dir_filter,
|
|
11
|
+
:max_iter,
|
|
12
|
+
:max_sec,
|
|
13
|
+
:options,
|
|
14
|
+
keyword_init: true
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
class ConfigData
|
|
18
|
+
def initialize(**opt)
|
|
19
|
+
opt[:output] ||= $stdout
|
|
20
|
+
opt[:gem_rbs_features] ||= []
|
|
21
|
+
opt[:dir_filter] ||= DEFAULT_DIR_FILTER
|
|
22
|
+
opt[:verbose] ||= 0
|
|
23
|
+
opt[:options] ||= {}
|
|
24
|
+
opt[:options] = {
|
|
25
|
+
type_depth_limit: 5,
|
|
26
|
+
pedantic_output: false,
|
|
27
|
+
show_errors: false,
|
|
28
|
+
stackprof: nil,
|
|
29
|
+
}.merge(opt[:options])
|
|
30
|
+
super(**opt)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check_dir_filter(path)
|
|
34
|
+
dir_filter.reverse_each do |cond, dir|
|
|
35
|
+
return cond unless dir
|
|
36
|
+
return cond if path.start_with?(dir)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
DEFAULT_DIR_FILTER = [
|
|
41
|
+
[:include],
|
|
42
|
+
[:exclude, RbConfig::CONFIG["prefix"]],
|
|
43
|
+
[:exclude, Gem.dir],
|
|
44
|
+
[:exclude, Gem.user_dir],
|
|
45
|
+
]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.analyze(config)
|
|
49
|
+
# Deploy the config to the TypeProf::Config (Note: This is thread unsafe)
|
|
50
|
+
if TypeProf.const_defined?(:Config)
|
|
51
|
+
TypeProf.send(:remove_const, :Config)
|
|
52
|
+
end
|
|
53
|
+
TypeProf.const_set(:Config, config)
|
|
54
|
+
|
|
55
|
+
if Config.options[:stackprof]
|
|
56
|
+
require "stackprof"
|
|
57
|
+
out = "typeprof-stackprof-#{ Config.options[:stackprof] }.dump"
|
|
58
|
+
StackProf.start(mode: Config.options[:stackprof], out: out, raw: true)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
scratch = Scratch.new
|
|
62
|
+
Builtin.setup_initial_global_env(scratch)
|
|
63
|
+
|
|
64
|
+
Config.gem_rbs_features.each do |feature|
|
|
65
|
+
Import.import_library(scratch, feature)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
prologue_ctx = Context.new(nil, nil, nil)
|
|
69
|
+
prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
|
|
70
|
+
prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
|
|
71
|
+
|
|
72
|
+
Config.rb_files.each do |file|
|
|
73
|
+
if file.respond_to?(:read)
|
|
74
|
+
iseq = ISeq.compile_str(file.read, file.to_s)
|
|
75
|
+
else
|
|
76
|
+
iseq = ISeq.compile(file)
|
|
77
|
+
end
|
|
78
|
+
ep, env = TypeProf.starting_state(iseq)
|
|
79
|
+
scratch.merge_env(ep, env)
|
|
80
|
+
scratch.add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
Config.rbs_files.each do |path|
|
|
84
|
+
Import.import_rbs_file(scratch, path)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
result = scratch.type_profile
|
|
88
|
+
|
|
89
|
+
if Config.output.respond_to?(:write)
|
|
90
|
+
scratch.report(result, Config.output)
|
|
91
|
+
else
|
|
92
|
+
open(Config.output, "w") do |output|
|
|
93
|
+
scratch.report(result, output)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
ensure
|
|
98
|
+
if Config.options[:stackprof] && defined?(StackProf)
|
|
99
|
+
StackProf.stop
|
|
100
|
+
StackProf.results
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.starting_state(iseq)
|
|
105
|
+
cref = CRef.new(:bottom, Type::Builtin[:obj], false) # object
|
|
106
|
+
recv = Type::Instance.new(Type::Builtin[:obj])
|
|
107
|
+
ctx = Context.new(iseq, cref, nil)
|
|
108
|
+
ep = ExecutionPoint.new(ctx, 0, nil)
|
|
109
|
+
locals = [Type.nil] * iseq.locals.size
|
|
110
|
+
env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
|
|
111
|
+
|
|
112
|
+
return ep, env
|
|
113
|
+
end
|
|
114
|
+
end
|