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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f530c84fe1b38000dc93982adac87c01d6d3a3516f8502e3de252d56428a12
4
- data.tar.gz: b799ff212fd16b59bb96f8b560252e687d206e9a3ba541eaa6033532108957e3
3
+ metadata.gz: 109bbaf7daec0e4dce2f23c17a73d9528c51441cf61f1e23f5dc5d3c2c47dbff
4
+ data.tar.gz: bbd47838c15aa0e2a12645a8c9d5f56b0587323e96d919240681d747e2b73696
5
5
  SHA512:
6
- metadata.gz: 6e11866f36a7570ba564bf2abe6912f2531f728e76c4afc32f9bfddc436ea03a86a996eb4d3ddd2bf8c24e9eeae0986b45f17f06575d80df21b812585976f1ba
7
- data.tar.gz: 8e990ceee15c1dba1cf529990fbb6e26a4f48946088549f51471c48ff1aeccfdc7cb8b6547c1105e00767263acee681db4340240f94c786b39bbeff842d501dc
6
+ metadata.gz: 6e1ff8245d59eb81f253544b9a1a0e6a54f154fb17634e739210d4320e96619d59b70f9efd6811f600ab67e52ea341d3d9a886ab2b00d397ede5594f23ce8340
7
+ data.tar.gz: 2723c535e5f42e13e419e2646607ba9a5ec0a90c266fd2a927e658b133703f658af0cdfc2f392c6acd7f6f96fbbb54019251163f2109b1624158a48e019a56f2
@@ -7,7 +7,7 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- ruby-version: [2.7, 3.0, head]
10
+ ruby-version: [2.7, 3.0,head]
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v2
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.15.3)
5
- rbs (>= 1.3.1)
4
+ typeprof (0.20.0)
5
+ rbs (>= 1.6.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -11,7 +11,7 @@ GEM
11
11
  docile (1.4.0)
12
12
  power_assert (2.0.0)
13
13
  rake (13.0.1)
14
- rbs (1.6.1)
14
+ rbs (1.6.2)
15
15
  simplecov (0.21.2)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
@@ -19,7 +19,7 @@ GEM
19
19
  simplecov-html (0.12.3)
20
20
  simplecov_json_formatter (0.1.3)
21
21
  stackprof (0.2.17)
22
- test-unit (3.4.2)
22
+ test-unit (3.4.4)
23
23
  power_assert
24
24
 
25
25
  PLATFORMS
data/exe/typeprof CHANGED
@@ -3,4 +3,8 @@
3
3
  require_relative "../lib/typeprof"
4
4
 
5
5
  config = TypeProf::CLI.parse(ARGV)
6
- TypeProf.analyze(config)
6
+ if config.options[:lsp]
7
+ TypeProf.start_lsp_server(config)
8
+ else
9
+ TypeProf.analyze(config)
10
+ end
@@ -43,6 +43,14 @@ module TypeProf
43
43
  end
44
44
  end
45
45
 
46
+ def detailed_source_location(pc)
47
+ if @iseq
48
+ @iseq.detailed_source_location(pc)
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
46
54
  def replace_cref(cref)
47
55
  Context.new(@iseq, cref, @mid)
48
56
  end
@@ -66,6 +74,14 @@ module TypeProf
66
74
  end
67
75
  end
68
76
 
77
+ def detailed_source_location(_pc)
78
+ if @caller_ep
79
+ @caller_ep.source_location
80
+ else
81
+ nil
82
+ end
83
+ end
84
+
69
85
  def replace_cref(cref)
70
86
  # What to do?
71
87
  end
@@ -101,6 +117,14 @@ module TypeProf
101
117
  def source_location
102
118
  @ctx.source_location(@pc)
103
119
  end
120
+
121
+ def detailed_source_location
122
+ @ctx.detailed_source_location(@pc)
123
+ end
124
+
125
+ def absolute_path
126
+ @ctx.iseq.absolute_path
127
+ end
104
128
  end
105
129
 
106
130
  class StaticEnv
@@ -287,6 +311,9 @@ module TypeProf
287
311
 
288
312
  @types_being_shown = []
289
313
  @namespace = nil
314
+
315
+ @lsp_completion = nil
316
+ @lsp_signature_help = CodeRangeTable.new
290
317
  end
291
318
 
292
319
  def add_entrypoint(iseq)
@@ -335,7 +362,7 @@ module TypeProf
335
362
  @subclasses = []
336
363
  end
337
364
 
338
- attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path, :subclasses
365
+ attr_reader :kind, :modules, :methods, :ivars, :cvars, :absolute_path, :subclasses
339
366
  attr_accessor :name, :klass_obj
340
367
 
341
368
  def mix_module(kind, mod, type_args, singleton, absolute_path)
@@ -350,24 +377,43 @@ module TypeProf
350
377
  end
351
378
 
352
379
  def get_constant(name)
353
- ty, = @consts[name]
354
- ty || Type.any # XXX: warn?
380
+ ty, locs = @consts[name]
381
+ ty = ty || Type.any # XXX: warn?
382
+ return ty, locs
355
383
  end
356
384
 
357
- def add_constant(name, ty, absolute_path)
385
+ def add_constant(name, ty, def_ep)
358
386
  if @consts[name]
359
387
  # XXX: warn!
388
+ _, eps = @consts[name]
389
+ @consts[name] = [ty, eps + [def_ep&.detailed_source_location]]
390
+ return
391
+ end
392
+ @consts[name] = [ty, [def_ep&.detailed_source_location]]
393
+ end
394
+
395
+ def consts
396
+ @consts.lazy.flat_map do |name, (ty, eps)|
397
+ eps.map do |ep|
398
+ [name, [ty, ep]]
399
+ end
360
400
  end
361
- @consts[name] = [ty, absolute_path]
362
401
  end
363
402
 
403
+ def add_class_open(name, open_ep)
404
+ ty, eps = @consts[name]
405
+ raise "call this only if the class is opened more than once" if ty.nil?
406
+ @consts[name] = [ty, eps + [open_ep&.detailed_source_location]]
407
+ end
408
+
409
+
364
410
  def adjust_substitution_for_module(mods, mid, mthd, subst, &blk)
365
411
  mods.each do |mod_def, type_args,|
366
412
  if mod_def.klass_obj.type_params && type_args
367
413
  subst2 = {}
368
414
  mod_def.klass_obj.type_params.zip(type_args) do |(tyvar, *), tyarg|
369
415
  tyvar = Type::Var.new(tyvar)
370
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
416
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
371
417
  end
372
418
  mod_def.adjust_substitution(false, mid, mthd, subst2, false, &blk)
373
419
  end
@@ -444,23 +490,23 @@ module TypeProf
444
490
  cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
445
491
  end
446
492
 
447
- def new_class(cbase, name, type_params, superclass, absolute_path)
493
+ def new_class(cbase, name, type_params, superclass, def_ep)
448
494
  show_name = cbase_path(cbase) + [name]
449
495
  idx = @class_defs.size
450
496
  if superclass
451
- @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
497
+ @class_defs[idx] = ClassDef.new(:class, show_name, def_ep&.absolute_path)
452
498
  @class_defs[superclass.idx].subclasses << idx unless superclass == :__root__
453
499
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
454
500
  @class_defs[idx].klass_obj = klass
455
501
  cbase ||= klass # for bootstrap
456
- add_constant(cbase, name, klass, absolute_path)
502
+ add_constant(cbase, name, klass, def_ep)
457
503
  return klass
458
504
  else
459
505
  # module
460
- @class_defs[idx] = ClassDef.new(:module, show_name, absolute_path)
506
+ @class_defs[idx] = ClassDef.new(:module, show_name, def_ep&.absolute_path)
461
507
  mod = Type::Class.new(:module, idx, type_params, nil, show_name)
462
508
  @class_defs[idx].klass_obj = mod
463
- add_constant(cbase, name, mod, absolute_path)
509
+ add_constant(cbase, name, mod, def_ep)
464
510
  return mod
465
511
  end
466
512
  end
@@ -519,7 +565,7 @@ module TypeProf
519
565
  subst2 = {}
520
566
  klass.superclass.type_params.zip(klass.superclass_type_args) do |(tyvar, *), tyarg|
521
567
  tyvar = Type::Var.new(tyvar)
522
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
568
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
523
569
  end
524
570
  subst = subst2
525
571
  end
@@ -601,29 +647,53 @@ module TypeProf
601
647
  nil
602
648
  end
603
649
 
650
+ def get_all_methods(klass, singleton, _include_subclasses)
651
+ names = {}
652
+
653
+ if klass.kind == :class
654
+ while klass != :__root__
655
+ # TODO: module
656
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
657
+ if singleton == singleton0
658
+ names[name] = true
659
+ end
660
+ end
661
+ klass = klass.superclass
662
+ end
663
+ else
664
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
665
+ if singleton == singleton0
666
+ names[name] = true
667
+ end
668
+ end
669
+ end
670
+
671
+ names
672
+ end
673
+
604
674
  def get_constant(klass, name)
605
675
  if klass == Type.any
606
- Type.any
676
+ [Type.any, nil]
607
677
  elsif klass.is_a?(Type::Class)
608
678
  @class_defs[klass.idx].get_constant(name)
609
679
  else
610
- Type.any
680
+ [Type.any, nil]
611
681
  end
612
682
  end
613
683
 
614
684
  def search_constant(cref, name)
615
685
  while cref != :bottom
616
- val = get_constant(cref.klass, name)
617
- return val if val != Type.any
686
+ ty, locs = get_constant(cref.klass, name)
687
+ return ty, locs if ty != Type.any
618
688
  cref = cref.outer
619
689
  end
620
690
 
621
- Type.any
691
+ return Type.any, nil
622
692
  end
623
693
 
624
- def add_constant(klass, name, value, user_defined)
694
+ def add_constant(klass, name, value, def_ep)
625
695
  if klass.is_a?(Type::Class)
626
- @class_defs[klass.idx].add_constant(name, value, user_defined)
696
+ @class_defs[klass.idx].add_constant(name, value, def_ep)
627
697
  end
628
698
  end
629
699
 
@@ -694,7 +764,13 @@ module TypeProf
694
764
  end
695
765
 
696
766
  def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
697
- @executed_iseqs << callee_ctx.iseq if callee_ctx.is_a?(Context)
767
+ if callee_ctx.is_a?(Context)
768
+ @executed_iseqs << callee_ctx.iseq
769
+ callee_type = callee_ctx.iseq.type
770
+ if caller_ep.ctx.is_a?(Context) && (callee_type == :method || callee_type == :block)
771
+ caller_ep.ctx.iseq&.add_called_iseq(caller_ep.pc, callee_ctx.iseq)
772
+ end
773
+ end
698
774
 
699
775
  @callsites[callee_ctx] ||= {}
700
776
  @callsites[callee_ctx][caller_ep] = ctn
@@ -743,23 +819,23 @@ module TypeProf
743
819
  end
744
820
 
745
821
  class VarTable
746
- Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths)
822
+ Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths, :write_eps)
747
823
 
748
824
  def initialize
749
825
  @tbl = {}
750
826
  end
751
827
 
752
828
  def add_read!(site, ep, &ctn)
753
- entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new)
829
+ entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
754
830
  entry.read_continuations[ep] = ctn
755
831
  entry.absolute_paths << ep.ctx.iseq.absolute_path if ep.ctx.is_a?(Context)
756
832
  ty = entry.type
757
833
  ty = Type.nil if ty == Type.bot
758
- ctn[ty, ep]
834
+ ctn[ty, ep, entry.write_eps]
759
835
  end
760
836
 
761
837
  def add_write!(site, ty, ep, scratch)
762
- entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
838
+ entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
763
839
  if ep
764
840
  if entry.rbs_declared
765
841
  unless Type.match?(ty, entry.type)
@@ -768,10 +844,11 @@ module TypeProf
768
844
  end
769
845
  end
770
846
  entry.absolute_paths << ep.ctx.iseq.absolute_path
847
+ entry.write_eps << ep
771
848
  end
772
849
  entry.type = entry.type.union(ty)
773
- entry.read_continuations.each do |ep, ctn|
774
- ctn[ty, ep]
850
+ entry.read_continuations.each do |read_ep, ctn|
851
+ ctn[ty, read_ep, [ep]]
775
852
  end
776
853
  end
777
854
 
@@ -815,7 +892,8 @@ module TypeProf
815
892
  recv.each_child do |recv|
816
893
  class_def, singleton = get_ivar(recv, var)
817
894
  next unless class_def
818
- class_def.ivars.add_write!([singleton, var], ty, ep, self)
895
+ site = [singleton, var]
896
+ class_def.ivars.add_write!(site, ty, ep, self)
819
897
  end
820
898
  end
821
899
 
@@ -846,18 +924,18 @@ module TypeProf
846
924
  end
847
925
 
848
926
  def error(ep, msg)
849
- p [ep.source_location, "[error] " + msg] if Config.verbose >= 2
927
+ p [ep.source_location, "[error] " + msg] if Config.current.verbose >= 2
850
928
  @errors << [ep, "[error] " + msg]
851
929
  end
852
930
 
853
931
  def warn(ep, msg)
854
- p [ep.source_location, "[warning] " + msg] if Config.verbose >= 2
932
+ p [ep.source_location, "[warning] " + msg] if Config.current.verbose >= 2
855
933
  @errors << [ep, "[warning] " + msg]
856
934
  end
857
935
 
858
936
  def reveal_type(ep, ty)
859
937
  key = ep.source_location
860
- puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.verbose >= 2
938
+ puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.current.verbose >= 2
861
939
  if @reveal_types[key]
862
940
  @reveal_types[key] = @reveal_types[key].union(ty)
863
941
  else
@@ -924,8 +1002,9 @@ module TypeProf
924
1002
  end
925
1003
  end
926
1004
 
927
- def type_profile
928
- start_time = tick = Time.now
1005
+ def type_profile(cancel_token = nil)
1006
+ cancel_token ||= Utils::TimerCancelToken.new(Config.current.max_sec)
1007
+ tick = Time.now
929
1008
  iter_counter = 0
930
1009
  stat_eps = Utils::MutableSet.new
931
1010
 
@@ -938,7 +1017,7 @@ module TypeProf
938
1017
  if entrypoint.is_a?(String)
939
1018
  file = entrypoint
940
1019
  next if @loaded_files[File.expand_path(file)]
941
- iseq = ISeq.compile(file)
1020
+ iseq, = ISeq.compile(file)
942
1021
  else
943
1022
  iseq = entrypoint
944
1023
  end
@@ -953,7 +1032,7 @@ module TypeProf
953
1032
  ep = @worklist.deletemin
954
1033
 
955
1034
  iter_counter += 1
956
- if Config.options[:show_indicator]
1035
+ if Config.current.options[:show_indicator]
957
1036
  tick2 = Time.now
958
1037
  if tick2 - tick >= 1
959
1038
  tick = tick2
@@ -962,7 +1041,7 @@ module TypeProf
962
1041
  end
963
1042
  end
964
1043
 
965
- if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
1044
+ if (Config.current.max_iter && Config.current.max_iter <= iter_counter) || cancel_token.cancelled?
966
1045
  @terminated = true
967
1046
  break
968
1047
  end
@@ -973,7 +1052,7 @@ module TypeProf
973
1052
 
974
1053
  break if @terminated
975
1054
 
976
- break unless Config.options[:stub_execution]
1055
+ break unless Config.current.options[:stub_execution]
977
1056
 
978
1057
  begin
979
1058
  iseq, (kind, dummy_continuation) = @pending_execution.first
@@ -981,7 +1060,7 @@ module TypeProf
981
1060
  @pending_execution.delete(iseq)
982
1061
  end while @executed_iseqs.include?(iseq)
983
1062
 
984
- puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
1063
+ puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.current.verbose >= 2
985
1064
 
986
1065
  break if !iseq
987
1066
  case kind
@@ -1000,7 +1079,7 @@ module TypeProf
1000
1079
  end
1001
1080
  end
1002
1081
 
1003
- $stderr.print "\r\e[K" if Config.options[:show_indicator]
1082
+ $stderr.print "\r\e[K" if Config.current.options[:show_indicator]
1004
1083
 
1005
1084
  stat_eps
1006
1085
  end
@@ -1017,13 +1096,70 @@ module TypeProf
1017
1096
  RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show(stat_eps, output)
1018
1097
  end
1019
1098
 
1099
+ def report_lsp
1100
+ errs = @errors.map do |ep, msg|
1101
+ [ep&.detailed_source_location, msg]
1102
+ end
1103
+
1104
+ res = RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show_lsp
1105
+
1106
+ path, loc = Config.current.options[:signature_help_loc]
1107
+ if path
1108
+ sig_help_res = []
1109
+ sig_help = @lsp_signature_help[loc]
1110
+ if sig_help
1111
+ recv = sig_help[:recv]
1112
+ mid = sig_help[:mid]
1113
+ singleton = sig_help[:singleton]
1114
+ mdefs = sig_help[:mdefs]
1115
+ node_id = sig_help[:node_id]
1116
+ mdefs.each do |mdef|
1117
+ case mdef
1118
+ when ISeqMethodDef
1119
+ ctxs = @iseq_method_to_ctxs[mdef]
1120
+ next unless ctxs
1121
+
1122
+ ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
1123
+
1124
+ method_name = mid
1125
+ method_name = "self.#{ method_name }" if singleton
1126
+
1127
+ str = recv.screen_name(self)
1128
+ str += singleton ? "." : "#"
1129
+ str += method_name.to_s
1130
+ str += ": "
1131
+ sig, _, sig_help = show_method_signature(ctx)
1132
+ offset = str.size
1133
+ sig_help = sig_help.transform_values {|r| (r.begin + offset ... r.end + offset) }
1134
+ str += sig
1135
+ sig_help_res << [str, sig_help, node_id]
1136
+ when AliasMethodDef
1137
+ # TODO
1138
+ when TypedMethodDef
1139
+ mdef.rbs_source&.[](1)&.each do |rbs|
1140
+ # TODO: sig_help
1141
+ sig_help_res << [rbs, {}, node_id]
1142
+ end
1143
+ end
1144
+ end
1145
+ end
1146
+ end
1147
+
1148
+ {
1149
+ sigs: res,
1150
+ errors: errs,
1151
+ completion: @lsp_completion,
1152
+ signature_help: sig_help_res,
1153
+ }
1154
+ end
1155
+
1020
1156
  def globalize_type(ty, env, ep)
1021
1157
  if ep.outer
1022
1158
  tmp_ep = ep
1023
1159
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1024
1160
  env = @return_envs[tmp_ep]
1025
1161
  end
1026
- ty.globalize(env, {}, Config.options[:type_depth_limit])
1162
+ ty.globalize(env, {}, Config.current.options[:type_depth_limit])
1027
1163
  end
1028
1164
 
1029
1165
  def localize_type(ty, env, ep, alloc_site = AllocationSite.new(ep))
@@ -1031,13 +1167,13 @@ module TypeProf
1031
1167
  tmp_ep = ep
1032
1168
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1033
1169
  target_env = @return_envs[tmp_ep]
1034
- target_env, ty = ty.localize(target_env, alloc_site, Config.options[:type_depth_limit])
1170
+ target_env, ty = ty.localize(target_env, alloc_site, Config.current.options[:type_depth_limit])
1035
1171
  merge_return_env(tmp_ep) do |env|
1036
1172
  env ? env.merge(target_env) : target_env
1037
1173
  end
1038
1174
  return env, ty
1039
1175
  else
1040
- return ty.localize(env, alloc_site, Config.options[:type_depth_limit])
1176
+ return ty.localize(env, alloc_site, Config.current.options[:type_depth_limit])
1041
1177
  end
1042
1178
  end
1043
1179
 
@@ -1099,13 +1235,16 @@ module TypeProf
1099
1235
  end
1100
1236
 
1101
1237
  def get_instance_variable(recv, var, ep, env)
1102
- add_ivar_read!(recv, var, ep) do |ty, ep|
1238
+ add_ivar_read!(recv, var, ep) do |ty, ep, write_eps|
1103
1239
  alloc_site = AllocationSite.new(ep)
1104
1240
  nenv, ty = localize_type(ty, env, ep, alloc_site)
1105
1241
  case ty
1106
1242
  when Type::Local
1107
1243
  @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
1108
1244
  end
1245
+ write_eps.each do |write_ep|
1246
+ ep.ctx.iseq.add_def_loc(ep.pc, write_ep.detailed_source_location)
1247
+ end
1109
1248
  yield ty, nenv
1110
1249
  end
1111
1250
  end
@@ -1122,7 +1261,7 @@ module TypeProf
1122
1261
  insn = ep.ctx.iseq.insns[ep.pc]
1123
1262
  operands = insn.operands
1124
1263
 
1125
- if Config.verbose >= 2
1264
+ if Config.current.verbose >= 2
1126
1265
  # XXX: more dedicated output
1127
1266
  puts "DEBUG: stack=%p" % [env.stack]
1128
1267
  puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn.insn, env.stack.size]
@@ -1291,8 +1430,10 @@ module TypeProf
1291
1430
  case flags & 7
1292
1431
  when 0, 2 # CLASS / MODULE
1293
1432
  type = (flags & 7) == 2 ? :module : :class
1294
- existing_klass = get_constant(cbase, id) # TODO: multiple return values
1433
+ existing_klass, = get_constant(cbase, id) # TODO: multiple return values
1295
1434
  if existing_klass.is_a?(Type::Class)
1435
+ # record re-opening location
1436
+ @class_defs[cbase.idx].add_class_open(id, ep)
1296
1437
  klass = existing_klass
1297
1438
  else
1298
1439
  if existing_klass != Type.any
@@ -1317,7 +1458,7 @@ module TypeProf
1317
1458
  superclass = nil
1318
1459
  end
1319
1460
  if cbase.is_a?(Type::Class)
1320
- klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1461
+ klass = new_class(cbase, id, [], superclass, ep)
1321
1462
  if superclass
1322
1463
  add_superclass_type_args!(klass, superclass.type_params.map { Type.any })
1323
1464
 
@@ -1631,7 +1772,7 @@ module TypeProf
1631
1772
  var, = operands
1632
1773
  ty = Type.builtin_global_variable_type(var)
1633
1774
  if ty
1634
- ty = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1775
+ ty, locs = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1635
1776
  env, ty = localize_type(ty, env, ep)
1636
1777
  env = env.push(ty)
1637
1778
  else
@@ -1776,20 +1917,23 @@ module TypeProf
1776
1917
  name, = operands
1777
1918
  env, (cbase, _allow_nil,) = env.pop(2)
1778
1919
  if cbase == Type.nil
1779
- ty = search_constant(ep.ctx.cref, name)
1920
+ ty, locs = search_constant(ep.ctx.cref, name)
1780
1921
  env, ty = localize_type(ty, env, ep)
1781
1922
  env = env.push(ty)
1782
1923
  elsif cbase == Type.any
1783
1924
  env = env.push(Type.any) # XXX: warning needed?
1784
1925
  else
1785
- ty = get_constant(cbase, name)
1926
+ ty, locs = get_constant(cbase, name)
1786
1927
  env, ty = localize_type(ty, env, ep)
1787
1928
  env = env.push(ty)
1788
1929
  end
1930
+ locs&.each do |loc|
1931
+ ep.ctx.iseq.add_def_loc(ep.pc, loc)
1932
+ end
1789
1933
  when :setconstant
1790
1934
  name, = operands
1791
1935
  env, (ty, cbase) = env.pop(2)
1792
- old_ty = get_constant(cbase, name)
1936
+ old_ty, = get_constant(cbase, name)
1793
1937
  if old_ty != Type.any # XXX???
1794
1938
  warn(ep, "already initialized constant #{ Type::Instance.new(cbase).screen_name(self) }::#{ name }")
1795
1939
  end
@@ -1798,7 +1942,7 @@ module TypeProf
1798
1942
  @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1799
1943
  end
1800
1944
  end
1801
- add_constant(cbase, name, globalize_type(ty, env, ep), ep.ctx.iseq.absolute_path)
1945
+ add_constant(cbase, name, globalize_type(ty, env, ep), ep)
1802
1946
 
1803
1947
  when :getspecial
1804
1948
  key, type = operands
@@ -2186,10 +2330,26 @@ module TypeProf
2186
2330
  merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
2187
2331
  end
2188
2332
 
2333
+ aargs.node_id = opt[:node_id]
2334
+
2189
2335
  return env, recv, mid, aargs
2190
2336
  end
2191
2337
 
2192
2338
  def do_send(recvs, mid, aargs, ep, env, &ctn)
2339
+ if mid == :__typeprof_lsp_completion
2340
+ names = {}
2341
+ recvs.each_child do |recv|
2342
+ case recv
2343
+ when Type::Void, Type::Any
2344
+ else
2345
+ klass, singleton, include_subclasses = recv.method_dispatch_info
2346
+ names.merge!(get_all_methods(klass, singleton, include_subclasses)) if klass
2347
+ end
2348
+ end
2349
+ @lsp_completion = names
2350
+ return ctn[Type.any, ep, env]
2351
+ end
2352
+
2193
2353
  recvs.each_child do |recv|
2194
2354
  case recv
2195
2355
  when Type::Void
@@ -2201,6 +2361,19 @@ module TypeProf
2201
2361
  klass, singleton, include_subclasses = recv.method_dispatch_info
2202
2362
  meths = get_method(klass, singleton, include_subclasses, mid) if klass
2203
2363
  if meths
2364
+ path, loc = Config.current.options[:signature_help_loc]
2365
+ if path && path == ep.ctx.iseq.path && mid != :inherited # XXX: too ad-hoc!!!
2366
+ path, code_range = ep&.detailed_source_location
2367
+ if path && code_range&.contain_loc?(loc)
2368
+ @lsp_signature_help[code_range] = {
2369
+ recv: recv,
2370
+ mid: mid,
2371
+ singleton: singleton,
2372
+ mdefs: meths,
2373
+ node_id: aargs.node_id,
2374
+ }
2375
+ end
2376
+ end
2204
2377
  meths.each do |meth|
2205
2378
  meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2206
2379
  end
@@ -2282,7 +2455,7 @@ module TypeProf
2282
2455
 
2283
2456
  bsig ||= BlockSignature.new([], [], nil, Type.nil)
2284
2457
 
2285
- bsig = bsig.screen_name(nil, self)
2458
+ bsig, = bsig.screen_name(nil, self)
2286
2459
  ret_ty = ret_ty.screen_name(self)
2287
2460
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2288
2461
 
@@ -2317,7 +2490,7 @@ module TypeProf
2317
2490
 
2318
2491
  begin
2319
2492
  @types_being_shown << farg_tys << ret_ty
2320
- farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2493
+ farg_tys, = farg_tys ? farg_tys.screen_name(nil, self) : ["(unknown)"]
2321
2494
  ret_ty = ret_ty.screen_name(self)
2322
2495
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2323
2496
 
@@ -2330,15 +2503,16 @@ module TypeProf
2330
2503
 
2331
2504
  def show_method_signature(ctx)
2332
2505
  farg_tys = @method_signatures[ctx]
2506
+ return nil unless farg_tys
2333
2507
  ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2334
2508
 
2335
2509
  untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2336
2510
 
2337
- farg_tys = farg_tys.screen_name(ctx.iseq, self)
2511
+ farg_tys, ranges = farg_tys.screen_name(ctx.iseq, self)
2338
2512
  ret_ty = ret_ty.screen_name(self)
2339
2513
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2340
2514
 
2341
- ["#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped]
2515
+ return "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped, ranges
2342
2516
  end
2343
2517
  end
2344
2518
  end
@@ -16,6 +16,7 @@ module TypeProf
16
16
  end
17
17
 
18
18
  attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
19
+ attr_accessor :node_id
19
20
 
20
21
  def globalize(caller_env, visited, depth)
21
22
  lead_tys = @lead_tys.map {|ty| ty.globalize(caller_env, visited, depth) }