typeprof 0.15.3 → 0.20.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 (366) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -1
  3. data/Gemfile.lock +5 -5
  4. data/doc/ide.md +81 -0
  5. data/doc/typeprof-for-ide-log.png +0 -0
  6. data/doc/typeprof-for-ide.png +0 -0
  7. data/exe/typeprof +5 -1
  8. data/lib/typeprof/analyzer.rb +235 -56
  9. data/lib/typeprof/arguments.rb +1 -0
  10. data/lib/typeprof/builtin.rb +23 -23
  11. data/lib/typeprof/cli.rb +23 -5
  12. data/lib/typeprof/code-range.rb +177 -0
  13. data/lib/typeprof/config.rb +41 -20
  14. data/lib/typeprof/container-type.rb +3 -0
  15. data/lib/typeprof/export.rb +191 -15
  16. data/lib/typeprof/import.rb +33 -9
  17. data/lib/typeprof/insns-def.rb +1 -0
  18. data/lib/typeprof/iseq.rb +224 -17
  19. data/lib/typeprof/lsp.rb +884 -0
  20. data/lib/typeprof/method.rb +15 -11
  21. data/lib/typeprof/type.rb +50 -42
  22. data/lib/typeprof/utils.rb +18 -1
  23. data/lib/typeprof/version.rb +1 -1
  24. data/lib/typeprof.rb +3 -5
  25. data/typeprof-lsp +3 -0
  26. data/typeprof.gemspec +2 -2
  27. data/vscode/.gitignore +5 -0
  28. data/vscode/.vscode/launch.json +16 -0
  29. data/vscode/.vscodeignore +7 -0
  30. data/vscode/README.md +22 -0
  31. data/vscode/development.md +31 -0
  32. data/vscode/package-lock.json +3249 -0
  33. data/vscode/package.json +71 -0
  34. data/vscode/sandbox/test.rb +24 -0
  35. data/vscode/src/extension.ts +299 -0
  36. data/vscode/tsconfig.json +15 -0
  37. metadata +21 -334
  38. data/smoke/alias.rb +0 -31
  39. data/smoke/alias2.rb +0 -21
  40. data/smoke/any-cbase.rb +0 -5
  41. data/smoke/any1.rb +0 -16
  42. data/smoke/any2.rb +0 -18
  43. data/smoke/arguments.rb +0 -17
  44. data/smoke/arguments2.rb +0 -56
  45. data/smoke/array-each.rb +0 -15
  46. data/smoke/array-each2.rb +0 -16
  47. data/smoke/array-each3.rb +0 -13
  48. data/smoke/array-ltlt.rb +0 -14
  49. data/smoke/array-ltlt2.rb +0 -17
  50. data/smoke/array-map.rb +0 -12
  51. data/smoke/array-map2.rb +0 -11
  52. data/smoke/array-map3.rb +0 -23
  53. data/smoke/array-mul.rb +0 -18
  54. data/smoke/array-plus1.rb +0 -11
  55. data/smoke/array-plus2.rb +0 -16
  56. data/smoke/array-pop.rb +0 -12
  57. data/smoke/array-range-aref.rb +0 -71
  58. data/smoke/array-replace.rb +0 -13
  59. data/smoke/array-s-aref.rb +0 -12
  60. data/smoke/array1.rb +0 -27
  61. data/smoke/array10.rb +0 -15
  62. data/smoke/array11.rb +0 -14
  63. data/smoke/array12.rb +0 -25
  64. data/smoke/array13.rb +0 -31
  65. data/smoke/array14.rb +0 -14
  66. data/smoke/array15.rb +0 -16
  67. data/smoke/array2.rb +0 -28
  68. data/smoke/array3.rb +0 -26
  69. data/smoke/array4.rb +0 -15
  70. data/smoke/array5.rb +0 -14
  71. data/smoke/array6.rb +0 -17
  72. data/smoke/array7.rb +0 -14
  73. data/smoke/array8.rb +0 -13
  74. data/smoke/array9.rb +0 -13
  75. data/smoke/attr-module.rb +0 -24
  76. data/smoke/attr-vis.rb +0 -43
  77. data/smoke/attr-vis.rbs +0 -4
  78. data/smoke/attr.rb +0 -28
  79. data/smoke/autoload.rb +0 -14
  80. data/smoke/backtrace.rb +0 -33
  81. data/smoke/block-ambiguous.rb +0 -37
  82. data/smoke/block-args1-rest.rb +0 -64
  83. data/smoke/block-args1.rb +0 -60
  84. data/smoke/block-args2-rest.rb +0 -64
  85. data/smoke/block-args2.rb +0 -60
  86. data/smoke/block-args3-rest.rb +0 -75
  87. data/smoke/block-args3.rb +0 -71
  88. data/smoke/block-blockarg.rb +0 -28
  89. data/smoke/block-kwarg.rb +0 -53
  90. data/smoke/block1.rb +0 -23
  91. data/smoke/block10.rb +0 -15
  92. data/smoke/block11.rb +0 -40
  93. data/smoke/block12.rb +0 -23
  94. data/smoke/block13.rb +0 -9
  95. data/smoke/block13.rbs +0 -3
  96. data/smoke/block14.rb +0 -18
  97. data/smoke/block2.rb +0 -15
  98. data/smoke/block3.rb +0 -38
  99. data/smoke/block4.rb +0 -19
  100. data/smoke/block5.rb +0 -21
  101. data/smoke/block6.rb +0 -21
  102. data/smoke/block7.rb +0 -19
  103. data/smoke/block8.rb +0 -28
  104. data/smoke/block9.rb +0 -13
  105. data/smoke/block_given.rb +0 -37
  106. data/smoke/blown.rb +0 -13
  107. data/smoke/break1.rb +0 -19
  108. data/smoke/break2.rb +0 -16
  109. data/smoke/break3.rb +0 -13
  110. data/smoke/break4.rb +0 -17
  111. data/smoke/case.rb +0 -17
  112. data/smoke/case2.rb +0 -18
  113. data/smoke/case3.rb +0 -17
  114. data/smoke/class-hierarchy.rb +0 -54
  115. data/smoke/class-hierarchy2.rb +0 -27
  116. data/smoke/class-new.rb +0 -15
  117. data/smoke/class.rb +0 -7
  118. data/smoke/class_eval.rb +0 -22
  119. data/smoke/class_instance_var.rb +0 -9
  120. data/smoke/class_method.rb +0 -25
  121. data/smoke/class_method2.rb +0 -21
  122. data/smoke/class_method3.rb +0 -29
  123. data/smoke/constant1.rb +0 -46
  124. data/smoke/constant2.rb +0 -36
  125. data/smoke/constant3.rb +0 -10
  126. data/smoke/constant4.rb +0 -12
  127. data/smoke/context-sensitive1.rb +0 -13
  128. data/smoke/cvar.rb +0 -31
  129. data/smoke/cvar2.rb +0 -17
  130. data/smoke/define_method.rb +0 -16
  131. data/smoke/define_method2.rb +0 -18
  132. data/smoke/define_method3.rb +0 -14
  133. data/smoke/define_method3.rbs +0 -3
  134. data/smoke/define_method4.rb +0 -15
  135. data/smoke/define_method4.rbs +0 -3
  136. data/smoke/define_method5.rb +0 -12
  137. data/smoke/define_method6.rb +0 -19
  138. data/smoke/define_method7.rb +0 -18
  139. data/smoke/demo.rb +0 -81
  140. data/smoke/demo1.rb +0 -17
  141. data/smoke/demo10.rb +0 -21
  142. data/smoke/demo11.rb +0 -12
  143. data/smoke/demo2.rb +0 -15
  144. data/smoke/demo3.rb +0 -17
  145. data/smoke/demo4.rb +0 -27
  146. data/smoke/demo5.rb +0 -16
  147. data/smoke/demo6.rb +0 -22
  148. data/smoke/demo7.rb +0 -15
  149. data/smoke/demo8.rb +0 -19
  150. data/smoke/demo9.rb +0 -18
  151. data/smoke/dummy-execution1.rb +0 -15
  152. data/smoke/dummy-execution2.rb +0 -16
  153. data/smoke/dummy_element.rb +0 -14
  154. data/smoke/ensure1.rb +0 -21
  155. data/smoke/enum_for.rb +0 -15
  156. data/smoke/enum_for2.rb +0 -17
  157. data/smoke/enumerator.rb +0 -16
  158. data/smoke/expandarray1.rb +0 -23
  159. data/smoke/expandarray2.rb +0 -24
  160. data/smoke/extended.rb +0 -38
  161. data/smoke/fib.rb +0 -28
  162. data/smoke/flip-flop.rb +0 -28
  163. data/smoke/flow1.rb +0 -17
  164. data/smoke/flow10.rb +0 -17
  165. data/smoke/flow11.rb +0 -17
  166. data/smoke/flow2.rb +0 -15
  167. data/smoke/flow3.rb +0 -15
  168. data/smoke/flow4.rb +0 -5
  169. data/smoke/flow5.rb +0 -20
  170. data/smoke/flow6.rb +0 -20
  171. data/smoke/flow7.rb +0 -21
  172. data/smoke/flow8.rb +0 -14
  173. data/smoke/flow9.rb +0 -12
  174. data/smoke/for.rb +0 -9
  175. data/smoke/freeze.rb +0 -12
  176. data/smoke/function.rb +0 -17
  177. data/smoke/gvar.rb +0 -14
  178. data/smoke/gvar2.rb +0 -15
  179. data/smoke/gvar2.rbs +0 -1
  180. data/smoke/hash-bot.rb +0 -12
  181. data/smoke/hash-fetch.rb +0 -28
  182. data/smoke/hash-merge-bang.rb +0 -12
  183. data/smoke/hash1.rb +0 -20
  184. data/smoke/hash2.rb +0 -13
  185. data/smoke/hash3.rb +0 -14
  186. data/smoke/hash4.rb +0 -11
  187. data/smoke/hash5.rb +0 -14
  188. data/smoke/huge_union.rb +0 -86
  189. data/smoke/identifier_keywords.rb +0 -17
  190. data/smoke/included.rb +0 -38
  191. data/smoke/inheritance.rb +0 -34
  192. data/smoke/inheritance2.rb +0 -35
  193. data/smoke/inherited.rb +0 -26
  194. data/smoke/initialize.rb +0 -28
  195. data/smoke/instance_eval.rb +0 -18
  196. data/smoke/instance_eval2.rb +0 -10
  197. data/smoke/instance_eval3.rb +0 -25
  198. data/smoke/instance_eval4.rb +0 -12
  199. data/smoke/int_times.rb +0 -15
  200. data/smoke/integer.rb +0 -11
  201. data/smoke/ivar.rb +0 -31
  202. data/smoke/ivar2.rb +0 -30
  203. data/smoke/ivar3.rb +0 -17
  204. data/smoke/ivar3.rbs +0 -3
  205. data/smoke/ivar4.rb +0 -21
  206. data/smoke/kernel-class.rb +0 -13
  207. data/smoke/keyword1.rb +0 -12
  208. data/smoke/keyword2.rb +0 -12
  209. data/smoke/keyword3.rb +0 -12
  210. data/smoke/keyword4.rb +0 -12
  211. data/smoke/keyword5.rb +0 -16
  212. data/smoke/kwrest.rb +0 -13
  213. data/smoke/kwrest.rbs +0 -3
  214. data/smoke/kwsplat1.rb +0 -43
  215. data/smoke/kwsplat2.rb +0 -13
  216. data/smoke/lit-complex.rb +0 -10
  217. data/smoke/lit-encoding.rb +0 -10
  218. data/smoke/manual-rbs.rb +0 -29
  219. data/smoke/manual-rbs.rbs +0 -3
  220. data/smoke/manual-rbs2.rb +0 -21
  221. data/smoke/manual-rbs2.rbs +0 -8
  222. data/smoke/manual-rbs3.rb +0 -13
  223. data/smoke/manual-rbs3.rbs +0 -3
  224. data/smoke/masgn1.rb +0 -14
  225. data/smoke/masgn2.rb +0 -18
  226. data/smoke/masgn3.rb +0 -13
  227. data/smoke/method_in_branch.rb +0 -23
  228. data/smoke/method_missing.rb +0 -29
  229. data/smoke/module1.rb +0 -29
  230. data/smoke/module2.rb +0 -28
  231. data/smoke/module3.rb +0 -33
  232. data/smoke/module4.rb +0 -35
  233. data/smoke/module5.rb +0 -17
  234. data/smoke/module6.rb +0 -40
  235. data/smoke/module_function1.rb +0 -29
  236. data/smoke/module_function2.rb +0 -29
  237. data/smoke/multiple-include.rb +0 -15
  238. data/smoke/multiple-superclass.rb +0 -28
  239. data/smoke/next1.rb +0 -21
  240. data/smoke/next2.rb +0 -17
  241. data/smoke/noname.rb +0 -9
  242. data/smoke/object-send1.rb +0 -23
  243. data/smoke/object-send2.rb +0 -10
  244. data/smoke/object-send3.rb +0 -18
  245. data/smoke/once.rb +0 -13
  246. data/smoke/optional1.rb +0 -14
  247. data/smoke/optional2.rb +0 -16
  248. data/smoke/optional3.rb +0 -11
  249. data/smoke/or_raise.rb +0 -18
  250. data/smoke/parameterizedd-self.rb +0 -20
  251. data/smoke/parameterizedd-self2.rb +0 -15
  252. data/smoke/pathname1.rb +0 -14
  253. data/smoke/pathname2.rb +0 -14
  254. data/smoke/pattern-match1.rb +0 -19
  255. data/smoke/pattern-match2.rb +0 -16
  256. data/smoke/prepend1.rb +0 -33
  257. data/smoke/prepend2.rb +0 -10
  258. data/smoke/prepend2.rbs +0 -9
  259. data/smoke/primitive_method.rb +0 -19
  260. data/smoke/printf.rb +0 -20
  261. data/smoke/proc.rb +0 -20
  262. data/smoke/proc2.rb +0 -17
  263. data/smoke/proc3.rb +0 -15
  264. data/smoke/proc4.rb +0 -12
  265. data/smoke/proc5.rb +0 -19
  266. data/smoke/proc6.rb +0 -13
  267. data/smoke/proc7.rb +0 -32
  268. data/smoke/public.rb +0 -38
  269. data/smoke/range.rb +0 -14
  270. data/smoke/rbs-alias.rb +0 -10
  271. data/smoke/rbs-alias.rbs +0 -4
  272. data/smoke/rbs-attr.rb +0 -27
  273. data/smoke/rbs-attr.rbs +0 -5
  274. data/smoke/rbs-attr2.rb +0 -11
  275. data/smoke/rbs-attr2.rbs +0 -3
  276. data/smoke/rbs-extend.rb +0 -10
  277. data/smoke/rbs-extend.rbs +0 -7
  278. data/smoke/rbs-interface.rb +0 -25
  279. data/smoke/rbs-interface.rbs +0 -12
  280. data/smoke/rbs-module.rb +0 -26
  281. data/smoke/rbs-module.rbs +0 -4
  282. data/smoke/rbs-opt-and-rest.rb +0 -10
  283. data/smoke/rbs-opt-and-rest.rbs +0 -3
  284. data/smoke/rbs-proc1.rb +0 -10
  285. data/smoke/rbs-proc1.rbs +0 -3
  286. data/smoke/rbs-proc2.rb +0 -21
  287. data/smoke/rbs-proc2.rbs +0 -3
  288. data/smoke/rbs-proc3.rb +0 -14
  289. data/smoke/rbs-proc3.rbs +0 -4
  290. data/smoke/rbs-record.rb +0 -18
  291. data/smoke/rbs-record.rbs +0 -4
  292. data/smoke/rbs-tyvar.rb +0 -19
  293. data/smoke/rbs-tyvar.rbs +0 -5
  294. data/smoke/rbs-tyvar2.rb +0 -21
  295. data/smoke/rbs-tyvar2.rbs +0 -9
  296. data/smoke/rbs-tyvar3.rb +0 -18
  297. data/smoke/rbs-tyvar3.rbs +0 -5
  298. data/smoke/rbs-tyvar4.rb +0 -37
  299. data/smoke/rbs-tyvar5.rb +0 -13
  300. data/smoke/rbs-tyvar5.rbs +0 -8
  301. data/smoke/rbs-tyvar6.rb +0 -18
  302. data/smoke/rbs-tyvar6.rbs +0 -12
  303. data/smoke/rbs-tyvar7.rb +0 -12
  304. data/smoke/rbs-tyvar7.rbs +0 -7
  305. data/smoke/rbs-vars.rb +0 -35
  306. data/smoke/rbs-vars.rbs +0 -7
  307. data/smoke/redo1.rb +0 -22
  308. data/smoke/redo2.rb +0 -23
  309. data/smoke/req-keyword.rb +0 -13
  310. data/smoke/require1.rb +0 -13
  311. data/smoke/require2.rb +0 -13
  312. data/smoke/rescue1.rb +0 -21
  313. data/smoke/rescue2.rb +0 -23
  314. data/smoke/rescue3.rb +0 -20
  315. data/smoke/rescue4.rb +0 -17
  316. data/smoke/respond_to.rb +0 -23
  317. data/smoke/rest-farg.rb +0 -11
  318. data/smoke/rest1.rb +0 -26
  319. data/smoke/rest2.rb +0 -31
  320. data/smoke/rest3.rb +0 -37
  321. data/smoke/rest4.rb +0 -19
  322. data/smoke/rest5.rb +0 -11
  323. data/smoke/rest6.rb +0 -12
  324. data/smoke/retry1.rb +0 -21
  325. data/smoke/return.rb +0 -14
  326. data/smoke/reveal.rb +0 -13
  327. data/smoke/simple.rb +0 -12
  328. data/smoke/singleton_class.rb +0 -8
  329. data/smoke/singleton_method.rb +0 -12
  330. data/smoke/step.rb +0 -18
  331. data/smoke/string-split.rb +0 -12
  332. data/smoke/struct-keyword_init.rb +0 -10
  333. data/smoke/struct.rb +0 -13
  334. data/smoke/struct2.rb +0 -25
  335. data/smoke/struct3.rb +0 -14
  336. data/smoke/struct4.rb +0 -7
  337. data/smoke/struct5.rb +0 -16
  338. data/smoke/struct6.rb +0 -15
  339. data/smoke/struct7.rb +0 -17
  340. data/smoke/stub-keyword.rb +0 -10
  341. data/smoke/super1.rb +0 -69
  342. data/smoke/super2.rb +0 -16
  343. data/smoke/super3.rb +0 -20
  344. data/smoke/super4.rb +0 -45
  345. data/smoke/super5.rb +0 -38
  346. data/smoke/svar1.rb +0 -13
  347. data/smoke/symbol-proc-attr.rb +0 -22
  348. data/smoke/symbol-proc-attr2.rb +0 -15
  349. data/smoke/symbol-proc-bot.rb +0 -13
  350. data/smoke/symbol-proc.rb +0 -25
  351. data/smoke/tap1.rb +0 -18
  352. data/smoke/toplevel.rb +0 -13
  353. data/smoke/two-map.rb +0 -18
  354. data/smoke/type_var.rb +0 -11
  355. data/smoke/typed_method.rb +0 -16
  356. data/smoke/uninitialize-var.rb +0 -13
  357. data/smoke/union-recv.rb +0 -35
  358. data/smoke/user-demo.rb +0 -15
  359. data/smoke/wrong-extend.rb +0 -27
  360. data/smoke/wrong-include.rb +0 -27
  361. data/smoke/wrong-include2.rb +0 -17
  362. data/smoke/wrong-rbs.rb +0 -15
  363. data/smoke/wrong-rbs.rbs +0 -7
  364. data/testbed/ao.rb +0 -297
  365. data/testbed/diff-lcs-entrypoint.rb +0 -4
  366. data/testbed/goodcheck-Gemfile.lock +0 -51
data/lib/typeprof/iseq.rb CHANGED
@@ -2,6 +2,17 @@ module TypeProf
2
2
  class ISeq
3
3
  # https://github.com/ruby/ruby/pull/4468
4
4
  CASE_WHEN_CHECKMATCH = RubyVM::InstructionSequence.compile("case 1; when Integer; end").to_a.last.any? {|insn,| insn == :checkmatch }
5
+ # https://github.com/ruby/ruby/blob/v3_0_2/vm_core.h#L1206
6
+ VM_ENV_DATA_SIZE = 3
7
+ # Check if Ruby 3.1 or later
8
+ RICH_AST = begin RubyVM::AbstractSyntaxTree.parse("1", keep_script_lines: true).node_id; true; rescue; false; end
9
+
10
+ FileInfo = Struct.new(
11
+ :node_id2node,
12
+ :definition_table,
13
+ :caller_table,
14
+ :created_iseqs,
15
+ )
5
16
 
6
17
  class << self
7
18
  def compile(file)
@@ -20,17 +31,67 @@ module TypeProf
20
31
  opt[:operands_unification] = false
21
32
  opt[:coverage_enabled] = false
22
33
 
34
+ parse_opts = {}
35
+ parse_opts[:keep_script_lines] = true if RICH_AST
36
+
37
+ unless defined?(RubyVM::InstructionSequence)
38
+ puts "Currently, TypeProf can work on a Ruby implementation that supports RubyVM::InstructionSequence, such as CRuby."
39
+ exit 1
40
+ end
41
+
23
42
  if str
43
+ node = RubyVM::AbstractSyntaxTree.parse(str, **parse_opts)
24
44
  iseq = RubyVM::InstructionSequence.compile(str, path, **opt)
25
45
  else
46
+ node = RubyVM::AbstractSyntaxTree.parse_file(path, **parse_opts)
26
47
  iseq = RubyVM::InstructionSequence.compile_file(path, **opt)
27
48
  end
28
49
 
29
- return new(iseq.to_a)
50
+ node_id2node = {}
51
+ build_ast_node_id_table(node, node_id2node) if RICH_AST
52
+
53
+ file_info = FileInfo.new(node_id2node, CodeRangeTable.new, CodeRangeTable.new, [])
54
+ iseq_rb = new(iseq.to_a, file_info)
55
+ iseq_rb.collect_local_variable_info(file_info) if RICH_AST
56
+ file_info.created_iseqs.each do |iseq|
57
+ iseq.unify_instructions
58
+ end
59
+
60
+ return iseq_rb, file_info.definition_table, file_info.caller_table
61
+ end
62
+
63
+ private def build_ast_node_id_table(node, tbl = {})
64
+ tbl[node.node_id] = node
65
+ node.children.each do |child|
66
+ build_ast_node_id_table(child, tbl) if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
67
+ end
68
+ tbl
69
+ end
70
+
71
+ def code_range_from_node(node)
72
+ CodeRange.new(
73
+ CodeLocation.new(node.first_lineno, node.first_column),
74
+ CodeLocation.new(node.last_lineno, node.last_column),
75
+ )
76
+ end
77
+
78
+ def find_node_by_id(node, id)
79
+ node = RubyVM::AbstractSyntaxTree.parse(node) if node.is_a?(String)
80
+
81
+ return node if id == node.node_id
82
+
83
+ node.children.each do |child|
84
+ if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
85
+ ret = find_node_by_id(child, id)
86
+ return ret if ret
87
+ end
88
+ end
89
+
90
+ nil
30
91
  end
31
92
  end
32
93
 
33
- Insn = Struct.new(:insn, :operands, :lineno)
94
+ Insn = Struct.new(:insn, :operands, :lineno, :code_range, :definitions)
34
95
  class Insn
35
96
  def check?(insn_cmp, operands_cmp = nil)
36
97
  return insn == insn_cmp && (!operands_cmp || operands == operands_cmp)
@@ -39,14 +100,19 @@ module TypeProf
39
100
 
40
101
  ISEQ_FRESH_ID = [0]
41
102
 
42
- def initialize(iseq)
103
+ def initialize(iseq, file_info)
104
+ file_info.created_iseqs << self
105
+
43
106
  @id = (ISEQ_FRESH_ID[0] += 1)
44
107
 
45
- _magic, _major_version, _minor_version, _format_type, _misc,
108
+ _magic, _major_version, _minor_version, _format_type, misc,
46
109
  @name, @path, @absolute_path, @start_lineno, @type,
47
110
  @locals, @fargs_format, catch_table, insns = *iseq
48
111
 
49
- convert_insns(insns)
112
+ fl, fc, ll, lc = misc[:code_location]
113
+ @iseq_code_range = CodeRange.new(CodeLocation.new(fl, fc), CodeLocation.new(ll, lc))
114
+
115
+ convert_insns(insns, misc[:node_ids] || [], file_info)
50
116
 
51
117
  add_body_start_marker(insns)
52
118
 
@@ -54,13 +120,13 @@ module TypeProf
54
120
 
55
121
  labels = create_label_table(insns)
56
122
 
57
- @insns = setup_insns(insns, labels)
123
+ @insns = setup_insns(insns, labels, file_info)
58
124
 
59
125
  @fargs_format[:opt] = @fargs_format[:opt].map {|l| labels[l] } if @fargs_format[:opt]
60
126
 
61
127
  @catch_table = []
62
128
  catch_table.map do |type, iseq, first, last, cont, stack_depth|
63
- iseq = iseq ? ISeq.new(iseq) : nil
129
+ iseq = iseq ? ISeq.new(iseq, file_info) : nil
64
130
  target = labels[cont]
65
131
  entry = [type, iseq, target, stack_depth]
66
132
  labels[first].upto(labels[last]) do |i|
@@ -69,17 +135,78 @@ module TypeProf
69
135
  end
70
136
  end
71
137
 
138
+ def_node_id = misc[:def_node_id]
139
+ if def_node_id && file_info.node_id2node[def_node_id] && (@type == :method || @type == :block)
140
+ def_node = file_info.node_id2node[def_node_id]
141
+ method_name_token_range = extract_method_name_token_range(def_node)
142
+ if method_name_token_range
143
+ @callers = Utils::MutableSet.new
144
+ file_info.caller_table[method_name_token_range] = @callers
145
+ end
146
+ end
147
+
72
148
  rename_insn_types
149
+ end
73
150
 
74
- unify_instructions
151
+ def extract_method_name_token_range(node)
152
+ case @type
153
+ when :method
154
+ regex = if node.type == :DEFS
155
+ /^def\s+(?:\w+)\s*\.\s*(\w+)/
156
+ else
157
+ /^def\s+(\w+)/
158
+ end
159
+ return nil unless node.source =~ regex
160
+ zero_loc = CodeLocation.new(1, 0)
161
+ name_start = $~.begin(1)
162
+ name_length = $~.end(1) - name_start
163
+ name_head_loc = zero_loc.advance_cursor(name_start, node.source)
164
+ name_tail_loc = name_head_loc.advance_cursor(name_length, node.source)
165
+ return CodeRange.new(
166
+ CodeLocation.new(
167
+ node.first_lineno + (name_head_loc.lineno - 1),
168
+ name_head_loc.lineno == 1 ? node.first_column + name_head_loc.column : name_head_loc.column
169
+ ),
170
+ CodeLocation.new(
171
+ node.first_lineno + (name_tail_loc.lineno - 1),
172
+ name_tail_loc.lineno == 1 ? node.first_column + name_tail_loc.column : name_tail_loc.column
173
+ ),
174
+ )
175
+ when :block
176
+ return ISeq.code_range_from_node(node)
177
+ end
75
178
  end
76
179
 
77
180
  def source_location(pc)
78
181
  "#{ @path }:#{ @insns[pc].lineno }"
79
182
  end
80
183
 
184
+ def detailed_source_location(pc)
185
+ code_range = @insns[pc].code_range
186
+ if code_range
187
+ [@path, code_range]
188
+ else
189
+ [@path]
190
+ end
191
+ end
192
+
193
+ def add_called_iseq(pc, callee_iseq)
194
+ if callee_iseq && @insns[pc].definitions
195
+ @insns[pc].definitions << [callee_iseq.path, callee_iseq.iseq_code_range]
196
+ end
197
+ if callee_iseq.callers
198
+ callee_iseq.callers << [@path, @insns[pc].code_range]
199
+ end
200
+ end
201
+
202
+ def add_def_loc(pc, detailed_loc)
203
+ if detailed_loc && @insns[pc].definitions
204
+ @insns[pc].definitions << detailed_loc
205
+ end
206
+ end
207
+
81
208
  attr_reader :name, :path, :absolute_path, :start_lineno, :type, :locals, :fargs_format, :catch_table, :insns
82
- attr_reader :id
209
+ attr_reader :id, :iseq_code_range, :callers
83
210
 
84
211
  def pretty_print(q)
85
212
  q.text "ISeq["
@@ -118,7 +245,7 @@ module TypeProf
118
245
  end
119
246
 
120
247
  # Remove lineno entry and convert instructions to Insn instances
121
- def convert_insns(insns)
248
+ def convert_insns(insns, node_ids, file_info)
122
249
  ninsns = []
123
250
  lineno = 0
124
251
  insns.each do |e|
@@ -129,7 +256,25 @@ module TypeProf
129
256
  ninsns << e
130
257
  when Array
131
258
  insn, *operands = e
132
- ninsns << Insn.new(insn, operands, lineno)
259
+ node_id = node_ids.shift
260
+ node = file_info.node_id2node[node_id]
261
+ if node
262
+ code_range = ISeq.code_range_from_node(node)
263
+ case insn
264
+ when :send, :invokesuper
265
+ opt, blk_iseq = operands
266
+ opt[:node_id] = node_id
267
+ if blk_iseq
268
+ misc = blk_iseq[4] # iseq's "misc" field
269
+ misc[:def_node_id] = node_id
270
+ end
271
+ when :definemethod, :definesmethod
272
+ iseq = operands[1]
273
+ misc = iseq[4] # iseq's "misc" field
274
+ misc[:def_node_id] = node_id
275
+ end
276
+ end
277
+ ninsns << Insn.new(insn, operands, lineno, code_range, nil)
133
278
  else
134
279
  raise "unknown iseq entry: #{ e }"
135
280
  end
@@ -156,7 +301,7 @@ module TypeProf
156
301
  i = insns.index(label) + 1
157
302
  end
158
303
 
159
- insns.insert(i, Insn.new(:_iseq_body_start, [], @start_lineno))
304
+ insns.insert(i, Insn.new(:_iseq_body_start, [], @start_lineno, nil, nil))
160
305
  end
161
306
  end
162
307
 
@@ -198,7 +343,7 @@ module TypeProf
198
343
  labels
199
344
  end
200
345
 
201
- def setup_insns(insns, labels)
346
+ def setup_insns(insns, labels, file_info)
202
347
  ninsns = []
203
348
  insns.each do |e|
204
349
  case e
@@ -208,7 +353,7 @@ module TypeProf
208
353
  operands = (INSN_TABLE[e.insn] || []).zip(e.operands).map do |type, operand|
209
354
  case type
210
355
  when "ISEQ"
211
- operand && ISeq.new(operand)
356
+ operand && ISeq.new(operand, file_info)
212
357
  when "lindex_t", "rb_num_t", "VALUE", "ID", "GENTRY", "CALL_DATA"
213
358
  operand
214
359
  when "OFFSET"
@@ -221,7 +366,12 @@ module TypeProf
221
366
  end
222
367
  end
223
368
 
224
- ninsns << Insn.new(e.insn, operands, e.lineno)
369
+ if e.code_range && should_collect_defs(e.insn)
370
+ definition = Utils::MutableSet.new
371
+ file_info.definition_table[e.code_range] = definition
372
+ end
373
+
374
+ ninsns << Insn.new(e.insn, operands, e.lineno, e.code_range, definition)
225
375
  else
226
376
  raise "unknown iseq entry: #{ e }"
227
377
  end
@@ -229,6 +379,63 @@ module TypeProf
229
379
  ninsns
230
380
  end
231
381
 
382
+ def should_collect_defs(insn_kind)
383
+ case insn_kind
384
+ when :send, :getinstancevariable, :getconstant
385
+ return true
386
+ else
387
+ return false
388
+ end
389
+ end
390
+
391
+ # Collect local variable use and definition info recursively
392
+ def collect_local_variable_info(file_info, absolute_level = 0, parent_variable_tables = {})
393
+ # e.g.
394
+ # variable_tables[abs_level][idx] = [[path, code_range]]
395
+ current_variables = []
396
+ variable_tables = parent_variable_tables.merge({
397
+ absolute_level => current_variables
398
+ })
399
+
400
+ dummy_def_range = CodeRange.new(
401
+ CodeLocation.new(@start_lineno, 0),
402
+ CodeLocation.new(@start_lineno, 1),
403
+ )
404
+ # Fill tail elements with parameters
405
+ (@fargs_format[:lead_num] || 0).times do |offset|
406
+ current_variables[VM_ENV_DATA_SIZE + @locals.length - offset - 1] ||= Utils::MutableSet.new
407
+ current_variables[VM_ENV_DATA_SIZE + @locals.length - offset - 1] << [@path, dummy_def_range]
408
+ end
409
+
410
+ @insns.each do |insn|
411
+ next unless insn.insn == :getlocal || insn.insn == :setlocal
412
+
413
+ idx = insn.operands[0]
414
+ # note: level is relative value to the current level
415
+ level = insn.operands[1]
416
+ target_abs_level = absolute_level - level
417
+ variable_tables[target_abs_level] ||= {}
418
+ variable_tables[target_abs_level][idx] ||= Utils::MutableSet.new
419
+
420
+ case insn.insn
421
+ when :setlocal
422
+ variable_tables[target_abs_level][idx] << [path, insn.code_range]
423
+ when :getlocal
424
+ file_info.definition_table[insn.code_range] = variable_tables[target_abs_level][idx]
425
+ end
426
+ end
427
+
428
+ @insns.each do |insn|
429
+ insn.operands.each do |operand|
430
+ next unless operand.is_a?(ISeq)
431
+ operand.collect_local_variable_info(
432
+ file_info, absolute_level + 1,
433
+ variable_tables
434
+ )
435
+ end
436
+ end
437
+ end
438
+
232
439
  def rename_insn_types
233
440
  @insns.each do |insn|
234
441
  case insn.insn
@@ -331,7 +538,7 @@ module TypeProf
331
538
  break unless @insns[j + 1].check?(:putobject, [true])
332
539
  break unless @insns[j + 2].check?(:getconstant) # TODO: support A::B::C
333
540
  break unless @insns[j + 3].check?(:topn, [1])
334
- break unless @insns[j + 4].check?(:send, [{:mid=>:===, :flag=>20, :orig_argc=>1}, nil])
541
+ break unless @insns[j + 4].check?(:send) && @insns[j + 4].operands[0].slice(:mid, :flag, :orig_argc) == {:mid=>:===, :flag=>20, :orig_argc=>1}
335
542
  break unless @insns[j + 5].check?(:branch)
336
543
  target_pc = @insns[j + 5].operands[1]
337
544
  break unless @insns[target_pc].check?(:pop, [])
@@ -497,7 +704,7 @@ module TypeProf
497
704
  sp += 1
498
705
  when :newhashfromarray
499
706
  raise NotImplementedError, "newhashfromarray"
500
- when :newrange, :tostring
707
+ when :newrange, :tostring, :anytostring
501
708
  sp -= 2
502
709
  return nil if sp <= 0
503
710
  sp += 1