typeprof 0.15.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/Gemfile.lock +4 -4
- data/exe/typeprof +5 -1
- data/lib/typeprof/analyzer.rb +261 -66
- data/lib/typeprof/arguments.rb +1 -0
- data/lib/typeprof/builtin.rb +30 -22
- data/lib/typeprof/cli.rb +22 -2
- data/lib/typeprof/code-range.rb +177 -0
- data/lib/typeprof/config.rb +43 -18
- data/lib/typeprof/container-type.rb +10 -1
- data/lib/typeprof/export.rb +199 -20
- data/lib/typeprof/import.rb +30 -4
- data/lib/typeprof/iseq.rb +504 -200
- data/lib/typeprof/lsp.rb +865 -0
- data/lib/typeprof/method.rb +17 -13
- data/lib/typeprof/type.rb +46 -38
- data/lib/typeprof/utils.rb +18 -1
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +3 -0
- data/smoke/array15.rb +1 -1
- data/smoke/array6.rb +2 -2
- data/smoke/array8.rb +1 -1
- data/smoke/block-args2.rb +3 -3
- data/smoke/block-args3.rb +4 -4
- data/smoke/break2.rb +1 -1
- data/smoke/gvar2.rb +0 -3
- data/smoke/hash-bot.rb +1 -1
- data/smoke/hash4.rb +1 -1
- data/smoke/identifier_keywords.rb +17 -0
- data/smoke/next2.rb +1 -1
- data/smoke/or_raise.rb +18 -0
- data/smoke/parameterizedd-self.rb +2 -2
- data/smoke/pattern-match1.rb +1 -6
- data/smoke/rbs-vars.rb +0 -3
- data/testbed/ao.rb +1 -1
- data/typeprof-lsp +3 -0
- data/typeprof.gemspec +1 -1
- data/vscode/.gitignore +5 -0
- data/vscode/.vscode/launch.json +16 -0
- data/vscode/.vscodeignore +7 -0
- data/vscode/README.md +22 -0
- data/vscode/development.md +31 -0
- data/vscode/package-lock.json +2211 -0
- data/vscode/package.json +71 -0
- data/vscode/sandbox/test.rb +24 -0
- data/vscode/src/extension.ts +285 -0
- data/vscode/tsconfig.json +15 -0
- metadata +20 -5
data/lib/typeprof/arguments.rb
CHANGED
data/lib/typeprof/builtin.rb
CHANGED
@@ -624,7 +624,7 @@ module TypeProf
|
|
624
624
|
end
|
625
625
|
|
626
626
|
def self.file_load(path, ep, env, scratch, &ctn)
|
627
|
-
iseq = ISeq.compile(path)
|
627
|
+
iseq, = ISeq.compile(path)
|
628
628
|
callee_ep, callee_env = TypeProf.starting_state(iseq)
|
629
629
|
scratch.merge_env(callee_ep, callee_env)
|
630
630
|
|
@@ -793,26 +793,27 @@ module TypeProf
|
|
793
793
|
|
794
794
|
Import.import_builtin(scratch)
|
795
795
|
|
796
|
-
Type::Builtin[:vmcore] = scratch.new_class(klass_obj, :VMCore, [], klass_obj, nil)
|
797
|
-
Type::Builtin[:int] = scratch.get_constant(klass_obj, :Integer)
|
798
|
-
Type::Builtin[:float] = scratch.get_constant(klass_obj, :Float)
|
799
|
-
Type::Builtin[:rational] = scratch.get_constant(klass_obj, :Rational)
|
800
|
-
Type::Builtin[:complex] = scratch.get_constant(klass_obj, :Complex)
|
801
|
-
Type::Builtin[:sym] = scratch.get_constant(klass_obj, :Symbol)
|
802
|
-
Type::Builtin[:str] = scratch.get_constant(klass_obj, :String)
|
803
|
-
Type::Builtin[:struct] = scratch.get_constant(klass_obj, :Struct)
|
804
|
-
Type::Builtin[:ary] = scratch.get_constant(klass_obj, :Array)
|
805
|
-
Type::Builtin[:hash] = scratch.get_constant(klass_obj, :Hash)
|
806
|
-
Type::Builtin[:io] = scratch.get_constant(klass_obj, :IO)
|
807
|
-
Type::Builtin[:proc] = scratch.get_constant(klass_obj, :Proc)
|
808
|
-
Type::Builtin[:range] = scratch.get_constant(klass_obj, :Range)
|
809
|
-
Type::Builtin[:regexp] = scratch.get_constant(klass_obj, :Regexp)
|
810
|
-
Type::Builtin[:matchdata] = scratch.get_constant(klass_obj, :MatchData)
|
811
|
-
Type::Builtin[:class] = scratch.get_constant(klass_obj, :Class)
|
812
|
-
Type::Builtin[:module] = scratch.get_constant(klass_obj, :Module)
|
813
|
-
Type::Builtin[:exc] = scratch.get_constant(klass_obj, :Exception)
|
814
|
-
Type::Builtin[:encoding] = scratch.get_constant(klass_obj, :Encoding)
|
815
|
-
Type::Builtin[:enumerator] = scratch.get_constant(klass_obj, :Enumerator)
|
796
|
+
Type::Builtin[:vmcore] , = scratch.new_class(klass_obj, :VMCore, [], klass_obj, nil)
|
797
|
+
Type::Builtin[:int] , = scratch.get_constant(klass_obj, :Integer)
|
798
|
+
Type::Builtin[:float] , = scratch.get_constant(klass_obj, :Float)
|
799
|
+
Type::Builtin[:rational] , = scratch.get_constant(klass_obj, :Rational)
|
800
|
+
Type::Builtin[:complex] , = scratch.get_constant(klass_obj, :Complex)
|
801
|
+
Type::Builtin[:sym] , = scratch.get_constant(klass_obj, :Symbol)
|
802
|
+
Type::Builtin[:str] , = scratch.get_constant(klass_obj, :String)
|
803
|
+
Type::Builtin[:struct] , = scratch.get_constant(klass_obj, :Struct)
|
804
|
+
Type::Builtin[:ary] , = scratch.get_constant(klass_obj, :Array)
|
805
|
+
Type::Builtin[:hash] , = scratch.get_constant(klass_obj, :Hash)
|
806
|
+
Type::Builtin[:io] , = scratch.get_constant(klass_obj, :IO)
|
807
|
+
Type::Builtin[:proc] , = scratch.get_constant(klass_obj, :Proc)
|
808
|
+
Type::Builtin[:range] , = scratch.get_constant(klass_obj, :Range)
|
809
|
+
Type::Builtin[:regexp] , = scratch.get_constant(klass_obj, :Regexp)
|
810
|
+
Type::Builtin[:matchdata] , = scratch.get_constant(klass_obj, :MatchData)
|
811
|
+
Type::Builtin[:class] , = scratch.get_constant(klass_obj, :Class)
|
812
|
+
Type::Builtin[:module] , = scratch.get_constant(klass_obj, :Module)
|
813
|
+
Type::Builtin[:exc] , = scratch.get_constant(klass_obj, :Exception)
|
814
|
+
Type::Builtin[:encoding] , = scratch.get_constant(klass_obj, :Encoding)
|
815
|
+
Type::Builtin[:enumerator] , = scratch.get_constant(klass_obj, :Enumerator)
|
816
|
+
Type::Builtin[:kernel] , = scratch.get_constant(klass_obj, :Kernel)
|
816
817
|
|
817
818
|
klass_vmcore = Type::Builtin[:vmcore]
|
818
819
|
klass_ary = Type::Builtin[:ary]
|
@@ -825,6 +826,7 @@ module TypeProf
|
|
825
826
|
scratch.set_custom_method(klass_vmcore, :"core#undef_method", Builtin.method(:vmcore_undef_method))
|
826
827
|
scratch.set_custom_method(klass_vmcore, :"core#hash_merge_kwd", Builtin.method(:vmcore_hash_merge_kwd))
|
827
828
|
scratch.set_custom_method(klass_vmcore, :"core#raise", Builtin.method(:vmcore_raise))
|
829
|
+
|
828
830
|
scratch.set_custom_method(klass_vmcore, :lambda, Builtin.method(:lambda))
|
829
831
|
scratch.set_singleton_custom_method(klass_obj, :"new", Builtin.method(:object_s_new))
|
830
832
|
scratch.set_custom_method(klass_obj, :p, Builtin.method(:kernel_p), false)
|
@@ -879,7 +881,13 @@ module TypeProf
|
|
879
881
|
# ENV: Hash[String, String]
|
880
882
|
str_ty = Type::Instance.new(Type::Builtin[:str])
|
881
883
|
env_ty = Type.gen_hash {|h| h[str_ty] = Type.optional(str_ty) }
|
882
|
-
scratch.add_constant(klass_obj, :ENV, env_ty,
|
884
|
+
scratch.add_constant(klass_obj, :ENV, env_ty, nil)
|
885
|
+
|
886
|
+
scratch.search_method(Type::Builtin[:kernel], false, :sprintf) do |mdefs,|
|
887
|
+
mdefs.each do |mdef|
|
888
|
+
scratch.add_method(klass_vmcore, :"core#sprintf", false, mdef)
|
889
|
+
end
|
890
|
+
end
|
883
891
|
end
|
884
892
|
end
|
885
893
|
end
|
data/lib/typeprof/cli.rb
CHANGED
@@ -18,11 +18,15 @@ module TypeProf
|
|
18
18
|
verbose = 1
|
19
19
|
|
20
20
|
options = {}
|
21
|
+
lsp_options = {}
|
21
22
|
dir_filter = nil
|
22
23
|
gem_rbs_features = []
|
23
24
|
gem_repo_dirs = []
|
24
25
|
show_version = false
|
25
26
|
max_sec = max_iter = nil
|
27
|
+
collection_path = RBS::Collection::Config::PATH
|
28
|
+
|
29
|
+
load_path_ext = []
|
26
30
|
|
27
31
|
opt.separator ""
|
28
32
|
opt.separator "Options:"
|
@@ -30,9 +34,12 @@ module TypeProf
|
|
30
34
|
opt.on("-q", "--quiet", "Do not display progress indicator") { options[:show_indicator] = false }
|
31
35
|
opt.on("-v", "--verbose", "Alias to --show-errors") { options[:show_errors] = true }
|
32
36
|
opt.on("--version", "Display typeprof version") { show_version = true }
|
33
|
-
opt.on("-I DIR", "Add DIR to the load/require path") {|v|
|
37
|
+
opt.on("-I DIR", "Add DIR to the load/require path") {|v| load_path_ext << v }
|
34
38
|
opt.on("-r FEATURE", "Require RBS of the FEATURE gem") {|v| gem_rbs_features << v }
|
35
39
|
opt.on("--repo DIR", "Add DIR to the RBS repository") {|v| gem_repo_dirs << v }
|
40
|
+
opt.on("--collection PATH", "File path of collection configuration") { |v| collection_path = v }
|
41
|
+
opt.on("--no-collection", "Ignore collection configuration") { collection_path = nil }
|
42
|
+
opt.on("--lsp", "LSP mode") {|v| options[:lsp] = true }
|
36
43
|
|
37
44
|
opt.separator ""
|
38
45
|
opt.separator "Analysis output options:"
|
@@ -68,8 +75,14 @@ module TypeProf
|
|
68
75
|
opt.on("--debug", "Display analysis log (for debugging purpose)") { verbose = 2 }
|
69
76
|
opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| options[:stackprof] = v.to_sym }
|
70
77
|
|
78
|
+
opt.separator ""
|
79
|
+
opt.separator "LSP options:"
|
80
|
+
opt.on("--port PORT", Integer, "Specify a port number to listen for requests on") {|v| lsp_options[:port] = v }
|
81
|
+
|
71
82
|
opt.parse!(argv)
|
72
83
|
|
84
|
+
$LOAD_PATH.unshift(*load_path_ext)
|
85
|
+
|
73
86
|
dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
|
74
87
|
rb_files = []
|
75
88
|
rbs_files = []
|
@@ -82,22 +95,29 @@ module TypeProf
|
|
82
95
|
end
|
83
96
|
|
84
97
|
puts "typeprof #{ VERSION }" if show_version
|
85
|
-
if rb_files.empty?
|
98
|
+
if rb_files.empty? && !options[:lsp]
|
86
99
|
exit if show_version
|
87
100
|
raise OptionParser::InvalidOption.new("no input files")
|
88
101
|
end
|
89
102
|
|
103
|
+
if !options[:lsp] && !lsp_options.empty?
|
104
|
+
exit if show_version
|
105
|
+
raise OptionParser::InvalidOption.new("lsp options with non-lsp mode")
|
106
|
+
end
|
107
|
+
|
90
108
|
ConfigData.new(
|
91
109
|
rb_files: rb_files,
|
92
110
|
rbs_files: rbs_files,
|
93
111
|
output: output,
|
94
112
|
gem_rbs_features: gem_rbs_features,
|
95
113
|
gem_repo_dirs: gem_repo_dirs,
|
114
|
+
collection_path: collection_path,
|
96
115
|
verbose: verbose,
|
97
116
|
dir_filter: dir_filter,
|
98
117
|
max_sec: max_sec,
|
99
118
|
max_iter: max_iter,
|
100
119
|
options: options,
|
120
|
+
lsp_options: lsp_options,
|
101
121
|
)
|
102
122
|
|
103
123
|
rescue OptionParser::InvalidOption
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module TypeProf
|
2
|
+
class CodeLocation
|
3
|
+
# In Ruby, lineno is 1-origin, and column is 0-origin
|
4
|
+
def initialize(lineno, column)
|
5
|
+
@lineno = lineno
|
6
|
+
@column = column
|
7
|
+
end
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
"(%d,%d)" % [@lineno, @column]
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :lineno, :column
|
14
|
+
|
15
|
+
def self.from_lsp(lsp_loc)
|
16
|
+
# In the Language Server Protocol, lineno and column are both 0-origin
|
17
|
+
CodeLocation.new(lsp_loc[:line] + 1, lsp_loc[:character])
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_lsp
|
21
|
+
{ line: @lineno - 1, character: @column }
|
22
|
+
end
|
23
|
+
|
24
|
+
def advance_cursor(offset, source_text)
|
25
|
+
new_lineno = @lineno
|
26
|
+
new_column = @column
|
27
|
+
while offset > 0
|
28
|
+
line_text = source_text.lines[new_lineno - 1]
|
29
|
+
if new_column + offset >= line_text.length
|
30
|
+
advanced = line_text.length - new_column
|
31
|
+
offset -= advanced
|
32
|
+
new_lineno += 1
|
33
|
+
new_column = 0
|
34
|
+
else
|
35
|
+
new_column += offset
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
CodeLocation.new(new_lineno, new_column)
|
40
|
+
end
|
41
|
+
|
42
|
+
def <=>(other)
|
43
|
+
ret = @lineno <=> other.lineno
|
44
|
+
return ret if ret != 0
|
45
|
+
@column <=> other.column
|
46
|
+
end
|
47
|
+
|
48
|
+
include Comparable
|
49
|
+
end
|
50
|
+
|
51
|
+
class CodeRange
|
52
|
+
def initialize(first, last)
|
53
|
+
@first, @last = first, last
|
54
|
+
end
|
55
|
+
|
56
|
+
def inspect
|
57
|
+
"%p-%p" % [@first, @last]
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :first
|
61
|
+
attr_reader :last
|
62
|
+
|
63
|
+
def self.from_lsp(lsp_range)
|
64
|
+
CodeRange.new(CodeLocation.from_lsp(lsp[:start]), CodeLocation.from_lsp(lsp[:end]))
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.from_rbs(rbs_loc)
|
68
|
+
CodeRange.new(
|
69
|
+
CodeLocation.new(rbs_loc.start_line, rbs_loc.start_column),
|
70
|
+
CodeLocation.new(rbs_loc.end_line, rbs_loc.end_column),
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_lsp
|
75
|
+
{ start: @first.to_lsp, end: @last.to_lsp }
|
76
|
+
end
|
77
|
+
|
78
|
+
def contain_loc?(loc)
|
79
|
+
@first <= loc && loc < @last
|
80
|
+
end
|
81
|
+
|
82
|
+
def contain?(other)
|
83
|
+
@first <= other.first && other.last <= @last
|
84
|
+
end
|
85
|
+
|
86
|
+
def overlap?(other)
|
87
|
+
if @first <= other.first
|
88
|
+
return @last > other.first
|
89
|
+
else
|
90
|
+
return @first < other.last
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class CodeRangeTable
|
96
|
+
Entry = Struct.new(:range, :value, :children)
|
97
|
+
|
98
|
+
class Entry
|
99
|
+
def inspect
|
100
|
+
"[%p, %p, %p]" % [range, value, children]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def initialize(list = [])
|
105
|
+
@list = list # Array[Entry]
|
106
|
+
end
|
107
|
+
|
108
|
+
def []=(range, value)
|
109
|
+
i_b = @list.bsearch_index {|e| e.range.last > range.first } || @list.size
|
110
|
+
i_e = @list.bsearch_index {|e| e.range.first >= range.last } || @list.size
|
111
|
+
if i_b < i_e
|
112
|
+
# for all i in i_b...i_e, @list[i] overlaps with the range
|
113
|
+
if i_e - i_b == 1
|
114
|
+
if range.contain?(@list[i_b].range)
|
115
|
+
@list[i_b] = Entry[range, value, CodeRangeTable.new(@list[i_b, 1])]
|
116
|
+
elsif @list[i_b].range.contain?(range)
|
117
|
+
@list[i_b].children[range] = value
|
118
|
+
else
|
119
|
+
raise
|
120
|
+
end
|
121
|
+
else
|
122
|
+
if range.contain?(@list[i_b].range) && range.contain?(@list[i_e - 1].range)
|
123
|
+
@list[i_b...i_e] = [Entry[range, value, CodeRangeTable.new(@list[i_b...i_e])]]
|
124
|
+
else
|
125
|
+
raise
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
@list[i_b, 0] = [Entry[range, value, CodeRangeTable.new]]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def [](loc)
|
134
|
+
e = @list.bsearch {|e| e.range.last > loc }
|
135
|
+
if e && e.range.contain_loc?(loc)
|
136
|
+
return e.children[loc] || e.value
|
137
|
+
end
|
138
|
+
return nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
if $0 == __FILE__
|
144
|
+
include TypeProf
|
145
|
+
cr1 = CodeRange.new(CodeLocation.new(1, 0), CodeLocation.new(1, 2))
|
146
|
+
cr2 = CodeRange.new(CodeLocation.new(1, 2), CodeLocation.new(1, 4))
|
147
|
+
cr3 = CodeRange.new(CodeLocation.new(2, 0), CodeLocation.new(2, 2))
|
148
|
+
cr4 = CodeRange.new(CodeLocation.new(2, 3), CodeLocation.new(2, 5))
|
149
|
+
cr1and2 = CodeRange.new(CodeLocation.new(1, 0), CodeLocation.new(1, 5))
|
150
|
+
cr3and4 = CodeRange.new(CodeLocation.new(2, 0), CodeLocation.new(2, 5))
|
151
|
+
[[cr1, "A"], [cr2, "B"], [cr3, "C"], [cr4, "D"], [cr1and2, "AB"], [cr3and4, "CD"]].permutation do |ary|
|
152
|
+
tbl = CodeRangeTable.new
|
153
|
+
ary.each do |cr, v|
|
154
|
+
tbl[cr] = v
|
155
|
+
end
|
156
|
+
values = []
|
157
|
+
[1, 2].each do |lineno|
|
158
|
+
(0..5).each do |column|
|
159
|
+
values << tbl[CodeLocation.new(lineno, column)]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
raise if values != ["A", "A", "B", "B", "AB", nil, "C", "C", "CD", "D", "D", nil]
|
163
|
+
end
|
164
|
+
|
165
|
+
source = <<~EOS
|
166
|
+
AB
|
167
|
+
CDE
|
168
|
+
F
|
169
|
+
EOS
|
170
|
+
a_loc = CodeLocation.new(1, 0)
|
171
|
+
b_loc = a_loc.advance_cursor(1, source)
|
172
|
+
raise unless b_loc.inspect == "(1,1)"
|
173
|
+
c_loc = a_loc.advance_cursor(3, source)
|
174
|
+
raise unless c_loc.inspect == "(2,0)"
|
175
|
+
f_loc = c_loc.advance_cursor(4, source)
|
176
|
+
raise unless f_loc.inspect == "(3,0)"
|
177
|
+
end
|
data/lib/typeprof/config.rb
CHANGED
@@ -7,11 +7,14 @@ module TypeProf
|
|
7
7
|
:output,
|
8
8
|
:gem_rbs_features,
|
9
9
|
:gem_repo_dirs,
|
10
|
+
:collection_path,
|
10
11
|
:verbose,
|
11
12
|
:dir_filter,
|
12
13
|
:max_iter,
|
13
14
|
:max_sec,
|
14
15
|
:options,
|
16
|
+
:lsp_options,
|
17
|
+
:lsp,
|
15
18
|
keyword_init: true
|
16
19
|
)
|
17
20
|
|
@@ -43,6 +46,9 @@ module TypeProf
|
|
43
46
|
union_width_limit: 10,
|
44
47
|
stackprof: nil,
|
45
48
|
}.merge(opt[:options])
|
49
|
+
opt[:lsp_options] = {
|
50
|
+
port: 0,
|
51
|
+
}.merge(opt[:lsp_options] || {})
|
46
52
|
super(**opt)
|
47
53
|
end
|
48
54
|
|
@@ -61,29 +67,39 @@ module TypeProf
|
|
61
67
|
]
|
62
68
|
end
|
63
69
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
TypeProf.send(:remove_const, :Config)
|
70
|
+
module Config
|
71
|
+
def self.current
|
72
|
+
Thread.current[:typeprof_config]
|
68
73
|
end
|
69
|
-
TypeProf.const_set(:Config, config)
|
70
74
|
|
71
|
-
|
75
|
+
def self.set_current(config)
|
76
|
+
Thread.current[:typeprof_config] = config
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.analyze(config, cancel_token = nil)
|
81
|
+
# Deploy the config to the TypeProf::Config (Note: This is thread local)
|
82
|
+
Config.set_current(config)
|
83
|
+
|
84
|
+
if Config.current.options[:stackprof]
|
72
85
|
require "stackprof"
|
73
|
-
out = "typeprof-stackprof-#{ Config.options[:stackprof] }.dump"
|
74
|
-
StackProf.start(mode: Config.options[:stackprof], out: out, raw: true)
|
86
|
+
out = "typeprof-stackprof-#{ Config.current.options[:stackprof] }.dump"
|
87
|
+
StackProf.start(mode: Config.current.options[:stackprof], out: out, raw: true)
|
75
88
|
end
|
76
89
|
|
77
90
|
scratch = Scratch.new
|
78
91
|
Builtin.setup_initial_global_env(scratch)
|
79
92
|
|
80
|
-
Config.gem_rbs_features.each do |feature|
|
93
|
+
Config.current.gem_rbs_features.each do |feature|
|
81
94
|
Import.import_library(scratch, feature)
|
82
95
|
end
|
83
96
|
|
97
|
+
collection_path = config.collection_path
|
98
|
+
Import.import_rbs_collection(scratch, collection_path) if collection_path&.exist?
|
99
|
+
|
84
100
|
rbs_files = []
|
85
101
|
rbs_codes = []
|
86
|
-
Config.rbs_files.each do |rbs|
|
102
|
+
Config.current.rbs_files.each do |rbs|
|
87
103
|
if rbs.is_a?(Array) # [String name, String content]
|
88
104
|
rbs_codes << rbs
|
89
105
|
else
|
@@ -95,30 +111,39 @@ module TypeProf
|
|
95
111
|
Import.import_rbs_code(scratch, name, content)
|
96
112
|
end
|
97
113
|
|
98
|
-
|
114
|
+
def_code_range_table = nil
|
115
|
+
caller_code_range_table = nil
|
116
|
+
Config.current.rb_files.each do |rb|
|
99
117
|
if rb.is_a?(Array) # [String name, String content]
|
100
|
-
iseq = ISeq.compile_str(*rb.reverse)
|
118
|
+
iseq, def_tbl, caller_tbl = ISeq.compile_str(*rb.reverse)
|
119
|
+
def_code_range_table ||= def_tbl
|
120
|
+
caller_code_range_table ||= caller_tbl
|
101
121
|
else
|
102
122
|
iseq = rb
|
103
123
|
end
|
104
124
|
scratch.add_entrypoint(iseq)
|
105
125
|
end
|
106
126
|
|
107
|
-
result = scratch.type_profile
|
127
|
+
result = scratch.type_profile(cancel_token)
|
128
|
+
|
129
|
+
if Config.current.options[:lsp]
|
130
|
+
return scratch.report_lsp, def_code_range_table, caller_code_range_table
|
131
|
+
end
|
108
132
|
|
109
|
-
if Config.output.respond_to?(:write)
|
110
|
-
scratch.report(result, Config.output)
|
133
|
+
if Config.current.output.respond_to?(:write)
|
134
|
+
scratch.report(result, Config.current.output)
|
111
135
|
else
|
112
|
-
open(Config.output, "w") do |output|
|
136
|
+
open(Config.current.output, "w") do |output|
|
113
137
|
scratch.report(result, output)
|
114
138
|
end
|
115
139
|
end
|
116
140
|
|
117
141
|
rescue TypeProfError => exc
|
118
|
-
exc.report(Config.output)
|
142
|
+
exc.report(Config.current.output)
|
119
143
|
|
144
|
+
return nil
|
120
145
|
ensure
|
121
|
-
if Config.options[:stackprof] && defined?(StackProf)
|
146
|
+
if Config.current.options[:stackprof] && defined?(StackProf)
|
122
147
|
StackProf.stop
|
123
148
|
StackProf.results
|
124
149
|
end
|
@@ -307,7 +307,11 @@ module TypeProf
|
|
307
307
|
def screen_name(scratch)
|
308
308
|
if @rest_ty == Type.bot
|
309
309
|
if @lead_tys.empty?
|
310
|
-
|
310
|
+
# This is heuristic: in general, an empty array is a wrong guess.
|
311
|
+
# Note that an empty array is representable as "[ ]" in RBS, but
|
312
|
+
# users often have to modify it to "Array[something]".
|
313
|
+
# In this term, "Array[untyped]" is considered more useful than "[ ]".
|
314
|
+
return "Array[untyped]"
|
311
315
|
end
|
312
316
|
s = @lead_tys.map do |ty|
|
313
317
|
ty.screen_name(scratch)
|
@@ -317,6 +321,9 @@ module TypeProf
|
|
317
321
|
end
|
318
322
|
|
319
323
|
"*[#{ squash.screen_name(scratch) }]"
|
324
|
+
rescue SystemStackError
|
325
|
+
p squash
|
326
|
+
exit!
|
320
327
|
end
|
321
328
|
|
322
329
|
def pretty_print(q)
|
@@ -673,6 +680,8 @@ module TypeProf
|
|
673
680
|
k_ty = k_ty.union(k)
|
674
681
|
v_ty = v_ty.union(v)
|
675
682
|
end
|
683
|
+
k_ty = Type.any if k_ty == Type.bot
|
684
|
+
v_ty = Type.any if v_ty == Type.bot
|
676
685
|
k_ty = k_ty.screen_name(scratch)
|
677
686
|
v_ty = v_ty.screen_name(scratch)
|
678
687
|
"Hash[#{ k_ty }, #{ v_ty }]"
|